我有一个部分内部表单,我通过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"})
但是,当数据库有数千名用户时,我怎样才能更有效地做到这一点以避免大的加载时间?
答案 0 :(得分:0)
您最好使用名为AutoComplete / LiveSearch
的文字框(如提及的Pardeep Saini
)。
我们之前已经这样做了:
你可以相对简单地实现这个目标:
= 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
设置一样......
他们这样做的方法是基本上使用与上面类似的原则(每个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: "£") %>
</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