Based on the response suggestions and my own further investigation here is my conclusion for the best way to get a large number of options in a form from an associated table.
It looks like autocomplete is the best solution. That is a regular text field but when you type in the second letter it pulls in the first 10 matches that it finds listing them below. Each additional letter refines the search. Since I am not highly skilled at JavaScript, rather than adding a plugin supplemented with my own JS as suggested, I opted to abstract the JS coding by using a gem, specifically rails-jquery-autocomplete.
Here are the steps:
Setup
Generate scaffolds:
rails generate scaffold City name state
rails generate scaffold Business name address city:references state zip
rake db:migrate
Install the gem. It uses jQuery-UI's autocomplete widget so install the rails gem for that as well.
# gemfile
gem 'jquery-ui-rails'
gem 'rails-jquery-autocomplete'
Add these to your javascript and stylesheet assets:
# app/assets/javascripts/application.js > put these after //= require jquery_ujs
//= require jquery-ui/autocomplete
//= require autocomplete-rails
# app/assets/stylesheets/application.css
*= require jquery-ui/autocomplete
Models
First create the association:
# app/model/city.rb
has_many :businesses
# app/model/business.rb
belongs_to :city
If you want to ensure that the city entered is in the cities table then add a validation:
# app/models/business.rb
validates :city, presence: true
The business table has a field for city_id not city name. We can create a virtual attribute in the business model file using getter and setter methods. There's probably a more up-to-date way to do this since I got it from a 4 year old RailsCast but it works.
#getter method
def city_name
city.try(:name)
end
#setter method
def city_name=(name)
self.city = City.find_by(name: name) if name.present?
end
Routes
Here's where the gem's magic kicks in. Add a route to the business REST resources formatted as autocomplete_model_attribute:
# config/routes.rb
resources :businesses do
get 'autocomplete_city_name' on: :collection
end
Controller
At the top of the controller call the autocomplete action passing it the class name and the attribute. By default autocomplete will match the text starting at the beginning of the word. If you want to search anywhere in the word set the 'full' option to true, otherwise leave it out.
# app/controllers/business_controller.rb
autocomplete :city, :name, full: true
Since we created a city_name virtual attribute in the business model we need to add it to the permitted params list
def business_params
params.require(:business).permit(:name, :address, :city_id, :state, :zip, :city_name)
end
Views
In the form to create or edit a new business instance change the city_id field to the city_name virtual attribute using the autocomplete_field helper. The 'data-auto-focus' option will automatically select the first value in the list. Leave it off if you don't want that.
# app/views/businesses/_form.html.erb
<div class="field">
<%= f.label :city_name %><br>
<%= f.autocomplete_field :city_name, autocomplete_city_name_businesses_path, 'data-auto-focus' => true %>
</div>
Done!