Getting rails3-autocomplete-jquery gem to work with Simple_Form with multiple inputs
So I am trying to implement multiple autocomplete using this gem and simple_form and I am getting an error.
I've tried this:
<%= f.input_field :neighborhood_id, collection: Neighborhood.order(:name), :url => autocomplete_neighborhood_name_searches_path, :as => :autocomplete, 'data-delimiter' => ',', :multiple => true, :class => "span8" %>
This is the error I am getting:
undefined method `to_i' for ["Alley Park, Madison"]:Array
In my parameters, it sends this to neighborhood_id
:
"search"=>{"neighborhood_id"=>["Alley Park, Madison"],
So it doesn't even use IDs for these values.
Does anyone have any ideas?
Edit 1:
In response to @jvnill's question, I am not doing anything with params[:search]
in the controller. Search creates a new record and performs a search listings
.
In my controller Searches, create
action, I just do this:
@search = Search.create!(params[:search])
Then mine search.rb
(i.e. the search model) has the following meaning:
def listings
@listings ||= find_listings
end
private
def find_listings
key = "%#{keywords}%"
listings = Listing.order(:headline)
listings = listings.includes(:neighborhood).where("listings.headline like ? or neighborhoods.name like ?", key, key) if keywords.present?
listings = listings.where(neighborhood_id: neighborhood_id) if neighborhood_id.present?
#truncated for brevity
listings
end
source to share
First of all, it would be easier if the form returns IDs instead of the neighborhood name. I have not used this stone yet, so I don’t know how it works. Reading in the readme says it will return ids, but I don't know why you are only getting names. I'm sure that once you know how to return ids, you can modify the code below to match.
You need to create a join table between neighborhood and lookup. Let's call this search_neighborhoods.
rails g model search_neighborhood neighborhood_id:integer search_id:integer
# dont forget to add indexes in the migration
After that, you want to customize your models.
# search.rb
has_many :search_neighborhoods
has_many :neighborhoods, through: :search_neighborhoods
# search_neighborhood.rb
belongs_to :search
belongs_to :neighborhood
# neighborhood.rb
has_many :search_neighborhoods
has_many :searches, through: :search_neighborhoods
Now that we have established the associations, we need to configure the setters and attributes
# search.rb
attr_accessible :neighborhood_names
# this will return a list of neighborhood names which is usefull with prepopulating
def neighborhood_names
neighborhoods.map(&:name).join(',')
end
# we will use this to find the ids of the neighborhoods given their names
# this will be called when you call create!
def neighborhood_names=(names)
names.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
# view
# you need to change your autocomplete to use the getter method
<%= f.input :neighborhood_names, url: autocomplete_neighborhood_name_searches_path, as: :autocomplete, input_html: { data: { delimiter: ',', multiple: true, class: "span8" } %>
the last but not the last is an update find_listings
def find_listings
key = "%#{keywords}%"
listings = Listing.order(:headline).includes(:neighborhood)
if keywords.present?
listings = listings.where("listings.headline LIKE :key OR neighborhoods.name LIKE :key", { key: "#{keywords}")
end
if neighborhoods.exists?
listings = listings.where(neighborhood_id: neighborhood_ids)
end
listings
end
What is it:)
UPDATE: Using f.input_field
# view
<%= f.input_field :neighborhood_names, url: autocomplete_neighborhood_name_searches_path, as: :autocomplete, data: { delimiter: ',' }, multiple: true, class: "span8" %>
# model
# 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
source to share
Your problem is how you collect values from the neighborhood of Model
Neighborhood.order(:name)
will return an array of names, you need to collect the id as well, but just display the names use collect and skip block, i believe this can do for you
Neighborhood.collect {|n| [n.name, n.id]}
Declare a region in the Neighborhood class to order it by name if you want to return its functionality, as this behavior is also present in the model.
edit> To add a scope / class method to the neighborhood model you usually do something like this
scope :desc, where("name DESC")
Than you can write something like:
Neighborhood.desc.all
which will return an array, which will allow .collect to be used, but there is another way to get those name and id attributes recognized by the select option.
source to share