当集合很大时,Rails集合选择

时间:2015-11-10 07:57:05

标签: ruby-on-rails ruby-on-rails-3

我有一个部分内部表单,我通过multiple: true集合选择关联用户:

    = f.collection_select(:user_ids, User.all, :id, :email, {selected: @limit_group.user_ids, include_blank: true}, {multiple: true, "data-placeholder" => "Add users to group"})

但是,当数据库有数千名用户时,我怎样才能更有效地做到这一点以避免大的加载时间?

1 个答案:

答案 0 :(得分:0)

您最好使用名为AutoComplete / LiveSearch的文字框(如提及的Pardeep Saini)。

我们之前已经这样做了:

enter image description here

你可以相对简单地实现这个目标:

= f.text_field :user_ids, placeholder: "Search for users"

然后你必须使用javascript

#app/assets/javascripts/application.js
$(document).on("keyup", "input[type=text]#user_ids", function(){
   $.getJSON("users/search", {name: $(this).val()}).done(function(json){
      var users = [];
      $.each(json.users, function(user) {
         users.push("<a href=\"#\" id="+ user.id +">" + user.name + "</a>");
      });
      $(".search").html(users).show();
   });
});

$(document).on("click", ".search a", function(e) {
   e.preventDefault();
   // add hidden field with user name to form
});

您必须使用相关的控制器操作进行备份:

#config/routes.rb
resources :users do
   get :search, on: :collection
end

#app/controllers/users_controller.rb
class UsersController < ApplicationController
  def search
     @users = User.where("name LIKE ?", "%" + params[:name] + "%")
     respond_to do |format| 
         format.json (render json: @users.to_json)
     end
  end
end

上面的代码应该重构。

-

要使用多个值,这将更多地涉及到。它可以完成,但您必须像StackOverflow中的tags设置一样......

enter image description here

他们这样做的方法是基本上使用与上面类似的原则(每个tag将是从搜索返回的数据)。

以下是我们在上面的化妆品示例中使用的实际代码:

#app/assets/javascripts/extra/jquery.livesearch.js
(function($) {
  $.searchbox = {}

  $.extend(true, $.searchbox, {
    settings: {
        url: 'search',
        param: 'search',
        dom_id: '#livesearch',
        minChars: 2,
        loading_css: '#livesearch_loading',
        del_id: '#livesearch_del'
    },

    loading: function() {
        $($.searchbox.settings.loading_css).show()
    },

    idle: function() {
        $($.searchbox.settings.loading_css).hide()
    },

    start: function() {
      $.searchbox.loading()
      $(document).trigger('before.searchbox')
    },

    stop: function() {
      $.searchbox.idle()
      $(document).trigger('after.searchbox')
    },

    kill: function() {
        $($.searchbox.settings.dom_id).fadeOut(50)
        $($.searchbox.settings.dom_id).html('')
        $($.searchbox.settings.del_id).fadeOut(100)
    },

    reset: function() {
        $($.searchbox.settings.dom_id).html('')
        $($.searchbox.settings.dom_id).fadeOut(50)
        $('#SearchSearch').val('')
        $($.searchbox.settings.del_id).fadeOut(100)
    },

    process: function(terms) {

        if(/\S/.test(terms)) {
            $.ajax({
                    type: 'GET',
                    url:  $.searchbox.settings.url,
                    data: {search: terms.trim()},
                    complete: function(data) {  
                        $($.searchbox.settings.del_id).fadeIn(50)
                        $($.searchbox.settings.dom_id).html(data.responseText)

                        if (!$($.searchbox.settings.dom_id).is(':empty')) {
                            $($.searchbox.settings.dom_id).fadeIn(100)
                        }

                        $.searchbox.stop();
                    }
                });
            return false;
        }else{
            $.searchbox.kill();
        }
    }
  });

  $.fn.searchbox = function(config) {
        var settings = $.extend(true, $.searchbox.settings, config || {})

        $(document).trigger('init.searchbox')
        $.searchbox.idle()

        return this.each(function() {
            var $input = $(this)

            $input
            .keyup(function() { 
                if ($input.val() != this.previousValue) {

                    if(/\S/.test($input.val().trim()) &&  $input.val().trim().length > $.searchbox.settings.minChars){ 
                        $.searchbox.start()
                        $.searchbox.process($input.val())
                    }else{
                        $.searchbox.kill()
                    }

                    this.previousValue = $input.val()

                }
            })
        })
    }
})(jQuery);

......和......

#app/assets/javascripts/application.js
$(document).ready( function() {

   var base_url = window.location.protocol + "//" + window.location.host;

    $('#SearchSearch').searchbox({
       url: base_url + '/search/',
       param: 'search',
       dom_id: '#livesearch',
       loading_css: '#livesearch_loading'
    })      

});
$(document).on('click', '#livesearch_del', function() { $.searchbox.reset(); }) 
$(document).on('submit', '#SearchForm', function() { $.searchbox.kill(); });
$(document).on('click', '.livesearch_results tr', function() { window.location = $('a:first', this).attr('href'); });

路线&amp;控制器:

#config/routes.rb
match 'search(/:search)', :to => 'products#search', :as => :search, via: [:get, :post]

#app/models/product.rb
class Product < ActiveRecord::Base
   def self.search(search)
        where("name LIKE ? OR description LIKE ?", "%#{search}%",  "%#{search}%").take(5)
   end
end

#app/controllers/product_controller.rb
class ProductsController < ApplicationController
    def search      
        @products = Product.search params[:search]
        respond_to do |format|
            format.js   { render :partial => "elements/livesearch", :locals => {:search => @products, :query => params[:search]} }
            format.html { 
                render :index
            }
        end
    end
end

观点:

#app/views/elements/_livesearch.html.erb
<div class="livesearch_container">
    <table class="livesearch_results">
        <%  unless search.blank? %>

            <% search.each_with_index do |item,i| %>

                <% pos ||= '' %>
                <% if (i == 0) then pos = 'first' end %>
                <% if (i == search.size - 1) then pos += ' last' end %>

                <tr data-link="<%= "/#{item.slug}" %>" class="<%= "#{pos}" %>">
                    <td class="image">
                        <% model = item.images.first || item.images.build %>
                        <%= image_tag(model.image.url(:thumb), :title => item.name, data: {"placement" => "left"}, :height => "85") %><br/>
                    </td>
                    <td class="information">
                        <%= link_to image_tag(item.brand.images.first.image.url(:thumb), :width => "55", :title => "View #{item.brand.name}"), "/#{item.brand.slug}", :class => "brand" if defined?(item.brand.images.first) %>
                        <div class="name"><%= link_to item.name, "/#{item.slug}" %></div>
                    </td>
                    <td class="price">
                        <%= number_to_currency(item.price, unit: "&pound;") %>
                    </td>
                </tr>
            <% end %>

            <tr class="results"><td colspan="3"><%= link_to "See all #{search.size} results here »", search_path(query) %></td></tr>

        <% else %>

            <tr class="results"><td colspan="3"><%= link_to 'No results found', search_path(query) %></td></tr>

        <% end %>
    </table> 
</div>

我还在这里gist发了.write