I have two associated models/tables
app/models/city.rb has_many :businesses Fields: id, city_name, state_code app/models/business.rb belongs_to :city Fields: id, biz_name, address, city_name, state_code, zip
In the new business form where you enter the business address, it is common to have a dropdown select box of states and/or countries. But for cities there are thousands so that wouldn't work. Is there a way to check that the city is listed in the cities table before allowing it to be saved? And possibly even putting the city_id in that field instead of the city_name?
Adding an auto-completion feature to your city_name
field would solve your problem.
First of all, because of the association between your Business
and City
objects, you WILL want to return a business[city_id]
parameter rather than a city_name
parameter (assuming you're using a form_for @business
helper).
If you're using jQuery, you can use the devbridge jQuery-Autocomplete plugin: https://github.com/devbridge/jQuery-Autocomplete
Create a simple method that returns a list of cities in JSON format (will require the jbuilder gem, which should be included by default in your Gemfile), for instance:
in app/controllers/businesses_controller.rb:
def ac_cities
@query = params[:query]
@results = City.where('city_name LIKE ?', "#{@query}%").order(city_name: :asc).limit(10)
respond_to do |format|
format.json
end
end
in app/views/businesses/ac_cities.json.jbuilder:
json.query @query
json.suggestions @results do |result|
json.value "<div data-id=\"#{result.id}\">#{result.city_name}</div>"
end
Initialize the devbridge instance and connect it to your city_name
field with CoffeeScript (or JS). The devbridge plugin also has an onSelect
feature that will allow you to populate the hidden business[city_id]
form field.
For instance, given the JSON returned above:
in app/assets/javascripts/businesses.js.coffee:
BusinessCitySelect = (suggestion) ->
$(this).next('#business_city_id').val(suggestion.value.match(/data-id="(\d+)"/i)[1])
$(this).val(suggestion.value.replace(new RegExp('<.*?\/?>', 'gi'), ''))
SearchACFormat = (suggestion, cv) ->
pattern = '(<div.*?>.*?)('+cv+').*?'
suggestion.value.replace(new RegExp(pattern, 'gi'), '$1<strong>$2<\/strong>')
$("#city_name").devbridgeAutocomplete({
serviceUrl: "/businesses/ac_cities.json",
formatResult: SearchACFormat,
onSelect: BusinessCitySelect,
noCache: true
})
the SearchACFormat
method makes use of devbridge's formatResult
feature to clean up our JSON for proper display within the city_name
input field while also providing highlighting.