How do I use select2-rails with simple_form?
Solution 1
The select2 plugin supports auto-completion. You can use the native auto-completion as follows:
<%= f.input_field :ac_neighborhood_ids,
data: {
placeholder: "Where do you want to live?",
saved: @search.neighborhoods.to_json,
url: autocomplete_neighborhood_name_searches_path
},
input_html: { class: "span8 ac-select2" }
%>
Javscript
$(document).ready(function() {
$('.ac-select2').each(function() {
var url = $(this).data('url');
var placeholder = $(this).data('placeholder');
var saved = jQuery.parseJSON($(this).data('saved'));
$(this).select2({
minimumInputLength: 2,
multiple: true,
placeholder : placeholder,
allowClear: true,
ajax: {
url: url,
dataType: 'json',
quietMillis: 500,
data: function (term) {
return {
name: term
};
},
results: function (data) {
return {results: data};
}
},
formatResult: function (item, page) {
return item.name;
},
formatSelection: function (item, page) {
return item.name;
},
initSelection : function (element, callback) {
if (saved) {
callback(saved);
}
}
});
});
});
Make sure the action at autocomplete_neighborhood_name_searches_path
returns a json array of hashes. Each hash should contain id
and name
fields. The term for auto-completion is passed via the query parameter name
.
def autocomplete_neighborhood_name
@neighborhood = Neighborhood.select("id, name").where("name LIKE ?", "#{params[:name]}%").order(:name).limit(10)
respond_to do |format|
format.json { render json: @neighborhood , :only => [:id, :name] }
end
end
Your search model:
class Search
attr_accessor :ac_neighborhood_ids
has_many :search_neighborhoods
has_many :neighborhoods, through: :search_neighborhoods
def ac_neighborhood_ids
neighborhood_ids.join(",")
end
def ac_neighborhoods
neighborhoods.map{|n| {:id => n.id, :name => n.name}}
end
def ac_neighborhood_ids=(ids)
search_neighborhoods.clear # remove the old values
ids.split(',').select(&:present?).map do |neighborhood_id|
search_neighborhoods.build neighborhood_id: neighborhood_id
end
end
end
Solution 2
I believe you need to attach select either to select tag (then it reads the data from it) or to input hidden tag, then you need to provide 'query' function. In your case it is attached to an input tag, and thus looks for a query function. Try setting as: :select
on your f.input_field
call.
marcamillion
Rails developer that loves finance, economics, business & tech.
Updated on November 20, 2020Comments
-
marcamillion over 3 years
This
select2
jquery library looks awesome. There is a Rails gem but it is very light on the documentation. I would like to generate a simple multiple drop-down menu, using autocomplete. How do I do that?This is my simple_form_for call:
<%= f.input_field :neighborhood_names, url: autocomplete_neighborhood_name_searches_path, as: :autocomplete, data: { delimiter: ',', placeholder: "Where do you want to live?"}, multiple: true, id: "selectWhereToLive", class: "span8" %>
I have successfully installed the
select2-rails
gem, but not quite sure how to get it working.I add this to my
home.js.coffee
file:jQuery -> $('#selectWhereToLive').select2()
And am getting this error:
Uncaught query function not defined for Select2 selectWhereToLive
Thoughts?
Edit 1:
The above
simple_form_for
call is producing this HTML:<input class="autocomplete optional span8" data-autocomplete="/searches/autocomplete_neighborhood_name" data-delimiter="," data-placeholder="Where do you want to live?" id="selectWhereToLive" multiple="multiple" name="search[neighborhood_names][]" size="30" type="text" url="/searches/autocomplete_neighborhood_name" value="" />
Indicating that the
id
attribute is being properly set.Edit 2 - Updated
As @moonfly suggested, I tried adding
as: :select
to thef.input_field
- both withas: :autocomplete
included and not included.The resulting HTML without
as: :autocomplete
was this:<input name="search[neighborhood_names][]" type="hidden" value="" /><select class="select optional span8" data-delimiter="," data-placeholder="Where do you want to live?" id="selectWhereToLive" multiple="multiple" name="search[neighborhood_names][]" url="/searches/autocomplete_neighborhood_name"><option value="true">Yes</option> <option value="false">No</option></select>
It pre-populates 2 option values 'Yes' and 'No'. Not quite sure why, but that is what it does.
Update
So I had changed the jquery selector to look for
input#ID
, and forgot. So I set that back and now it is generating the select box - but it is giving me those 2 Yes & No options. Not quite sure why it is doing that. It's not returning the values in from myurl
attribute.Edit 3
@harish-shetty's suggestion seems to be working. But now, after it has successfully found the records via autocomplete and using the select2 menu, it is bypassing the setter method I have on my
search.rb
model.Basically, what I want to happen is, once the user has finished filling out the form - and I have all the IDs/names for the neighborhoods they want, I want to create a new record in
search_neighborhoods
for those IDs.So these are the methods I have:
Search.rb def neighborhood_names neighborhoods.map(&:name).join(',') end # we need to put [0] because it returns an array with a single element containing # the string of comma separated neighborhoods def neighborhood_names=(names) names[0].split(',').each do |name| next if name.blank? if neighborhood = Neighborhood.find_by_name(name) search_neighborhoods.build neighborhood_id: neighborhood.id end end end
My
SearchController.rb
def autocomplete_neighborhood_name @neighborhood = Neighborhood.select("id, name").where("name LIKE ?", "#{params[:name]}%").order(:name).limit(10) respond_to do |format| format.json { render json: @neighborhood , :only => [:id, :name] } end end
This is what a request looks like right now - which shows that no
search_neighborhood
records are being created:Started POST "/searches" for 127.0.0.1 at 2013-03-06 04:09:55 -0500 Processing by SearchesController#create as HTML Parameters: {"utf8"=>"✓", "authenticity_token"=>"7SeA=", "search"=>{"boro_id"=>"", "neighborhood_names"=>"1416,1394", "property_type_id"=>"", "min_price"=>"", "max_price"=>"", "num_bedrooms"=>"", "num_bathrooms"=>""}} Neighborhood Load (0.5ms) SELECT "neighborhoods".* FROM "neighborhoods" WHERE "neighborhoods"."name" = '1' LIMIT 1 (0.3ms) BEGIN SQL (0.8ms) INSERT INTO "searches" ("amenity_id", "boro_id", "created_at", "keywords", "listing_type_id", "max_price", "min_price", "neighborhood_id", "num_bathrooms", "num_bedrooms", "property_type_id", "square_footage", "updated_at") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13) RETURNING "id" [["amenity_id", nil], ["boro_id", nil], ["created_at", Wed, 06 Mar 2013 09:09:55 UTC +00:00], ["keywords", nil], ["listing_type_id", nil], ["max_price", nil], ["min_price", nil], ["neighborhood_id", nil], ["num_bathrooms", nil], ["num_bedrooms", nil], ["property_type_id", nil], ["square_footage", nil], ["updated_at", Wed, 06 Mar 2013 09:09:55 UTC +00:00]] (32.2ms) COMMIT Redirected to http://localhost:3000/searches/29
-
marcamillion about 11 yearsCan I have two
as:
calls? One is currentlyas: :autocomplete
. -
marcamillion about 11 yearsI updated the question with the HTML output based on your suggestion. In short, it doesn't work :(
-
moonfly about 11 yearsno, only one. if you need to keep it as: :autocomplete, you'll have to define the 'query' function.
-
marcamillion about 11 yearsYah....even just
as: :select
doesn't work...it produces thoseYes/No
option value fields, for w/e reason. That is strange because the data returned from the URL call shouldn't beyes/no
. It should be a name. -
moonfly about 11 yearsfor select you need to provide collection with all the values. check github.com/plataformatec/simple_form#collections, for example. in your case, looks like you have no other way but to create a 'query' function which will retrieve the values from /searches/autocomplete_neighbourhood_names. so, forget I suggested to do
as: :select
, concentrate on writing 'query' -
marcamillion about 11 yearsOk...can you give me an example of
query
. Also, I know that thecollections
method insimple_form
requires that....but because I am using therails3-jquery-autocomplete
gem - github.com/crowdint/rails3-jquery-autocomplete it works without it. Meaning, that if I don't try and use theselect2()
jQuery plugin, and I type in the box...it will return the right info from the db - like I want. It's just that it looks ugly and I would much prefer the presentation be handled byselect2
. Once I try it this way though, the correct data is not returned. -
moonfly about 11 yearswell, I'm not an expert in select2, unfortunately. but you can find examples of
query
in select2 documentation: ivaynberg.github.com/select2/index.html#data, or even more relevant: ivaynberg.github.com/select2/index.html#ajax. -
marcamillion about 11 yearsYeh...and that's the issue....how do I make that work with simple_form. I know doing it manually is one way....but I am already using the rails3-jquery-autocomplete gem + simple_form.
-
marcamillion about 11 yearsHrmm....I was using the
rails3-jquery-autocomplete
gem - github.com/crowdint/rails3-jquery-autocomplete - so that generated thatautocomplete_neighborhood_name_searches_path
based on a declaration I put at the top of my controllers. Should I get rid of that declaration and create the actions manually? If so, which controller should I create the action on? MySearch
controller? That's where autocomplete is declared now. -
Harish Shetty about 11 yearsThat's how I have done it in the past. You should add the action in the
search
controller and register it as acollection
action in your route file. When every-thing works you should see the auto-completion work like this example: ivaynberg.github.com/select2/#ajax -
marcamillion about 11 yearsSo here is the last missing piece of the puzzle....now I finally got it working - but when it executes the search, it is bypassing my setter method in my
search.rb
model. I will update the question with more code. -
marcamillion about 11 yearsI also added log output from a request, that shows that it is skipping my setter method.
-
Harish Shetty about 11 yearsThe select2 plugin returns the ids, so it is better to pass rename the field to
neighborhood_ids
. I have updated my answer. If you need to subsequently edit the saved form, you need to add additional code to get it to work. -
marcamillion about 11 yearsNice....one last thing...why does this return an empty array as the first result? E.g.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"7SekQifiGWn77fjA=", "search"=>{"boro_id"=>"", "neighborhood_ids"=>"[],1416,1411,1676"}}
-
Harish Shetty about 11 yearsOh, it is because of the change I did. I have updated the Search model again. Take a look.
-
Harish Shetty about 11 yearsUpdated the answer to support the loading of saved data in the Edit mode. Hopefully it works for you. I am glad that somebody else is trying to use auto-completion with
select2
. It took me a while to get it working. May be I should create a gem to make it easy for rest of the crowd. -
Harish Shetty about 11 yearsGood thing is, this solution is generic. So you will be able to provide auto-completion support for any field as long as you pass the correct class, url and saved data.
-
marcamillion about 11 yearsSo now I am getting a nil error -
undefined method 'neighborhoods' for nil:NilClass
at this line:saved: @search.neighborhoods.to_json,
. By the way...I added a,
because you forgot that, for that line. -
Harish Shetty about 11 yearsI was assuming that you had a member variable called @search in your controller. Change that to whatever variable you are using with the form. (i.e.
saved: @search.neighborhoods.to_json
) -
marcamillion about 11 yearsWell...here is the thing...in my
create
action for mySearch
controller, I have an instance variable called@search
, but in myautocomplete_neighborhood_name
action, I only have a@neighborhood
instance variable. Which action are you referring to? -
marcamillion about 11 yearsOh...and to make matters more interesting, this form is on my
views/home/index.html.erb
- so technically it's not on either myneighborhood
orsearch
page. -
marcamillion about 11 yearsIf you ignore that error, I commented it out for now (partially because I may not need that functionality right now), I am getting this error:
undefined method 'name' for #<SearchNeighborhood:0x007fd93d3914f8>
at this line:search_neighborhoods.map{|n| {:id => n.id, :name => n.name}}
. So I changed that to be...:id => n.neighborhood_id, :name => n.neighborhood.name
But that didn't work. That returned a genericundefined method 'name' for nil:NilClass
at the same line. Thoughts? -
Harish Shetty about 11 yearsIt looks like you have a
has_many :through
relationship in yourSearch
model. I have changed the code to use a new name for the ac field. This should probably take care of the issue. -
marcamillion about 11 yearsYes....perfect. That works and I did have a HMT in the
Search
model. My bad...guess I should have specified that earlier. Thanks again dude. Really appreciate the persevering with me....many a SO Answerers wouldn't. Thanks much! -
Harish Shetty about 11 yearsIt is good that you got it to work. I will let you know when I create the gem. BTW, I updated the
ac_neighborhood_ids=
method to clear the old old neighborhoods. Otherwise you will accumulate the neighborhoods. -
marcamillion about 11 yearsThanks much...never even considered that.
-
marcamillion about 11 yearsIs there any reason the
placeholder
doesn't work? I even replaced theplaceholder
attribute on theselect2
call withplaceholder: "Where do you want to live?"
i.e. a string rather than a variable that holds the value of thedata-placeholder
attribute and that doesn't work. So it seems, for whatever reason, theplaceholder
attribute on the.select2
is not passing the correct value to the field. Thoughts? -
Harish Shetty about 11 yearsIt works for me. According to
select2
documentation you can set the thedata-placeholder
attribute in the markup. I am able to reproduce your issue at jsfiddle.net/ZNjgc. You should file a issue at the select2 github issue list. -
marcamillion about 11 yearsI will do that. Thanks for doing JSFiddle.
-
marcamillion about 11 yearsWant to take a look at the response - github.com/ivaynberg/select2/issues/1003#issuecomment-14645394 In this code in your answer, it checks for the saved variable and then it returns the
saved
object in the callback. But for some reason, it seems to be doing that even on the first search. I also see it in this Fiddle - jsfiddle.net/ZNjgc/3 - you will see on first load, in the search field is[]
. Is that thesaved
functionality? -
kuboon over 8 yearsselect2 doesn't support autocomplete. if you want to use both at once, it is javascript matter, not rails.