Adding a Drop-down List in Rails with a Foreign Key


Setting up a foreign key relationship in Rails is easy, however, the form for the relationship proved to be a bit tricky. Ideally, you want the foreign key to be selected if it’s set in the show view and you want it to save in the new and edit views. Here is how to make that happen.

I’ll start from scratch here. I’m assuming you have a shell open at the root of your Rails project. We’ll make two models that have a foreign key relationship. Any Address can have one state. Address has the UI, so use the scaffold generator. It doesn’t make much sense for State to have a UI, so just use the model generator. Obviously you could write these yourself as well.

rails g scaffold Address
rails g model State name:string

Next we’ll want to add the states as a seed, so add this to seeds.rb in the db directory

State.create([
  { name: 'Alabama'    },
  { name: 'Alaska'     },
  { name: 'Arizona'    },
  { name: 'Arkansas'   },
  { name: 'California' }
  #All other states...
])

To add the foreign key, add a belongs_to relationship in the Address migration in the db/migrate directory. It’ll look like this

class CreateAddresses < ActiveRecord::Migration
  def change
    create_table :addresses do |t|
      t.belongs_to :state
      t.timestamps
    end
  end
end

Also add a belongs_to relationship to the Address model in app/models/address.rbBootstrap. You can add whatever class you want.

<%= f.collection_select(:state_id, State.all, :id, :name, { :prompt => 'Select a State', :selected => @address.state_id }, { class: 'form-control' }) %>

Fire up the rails development server by typing rails s at the shell. Visit http://localhost:3000/addresses/new in the browser and it'll look like this:

rails s

select1select2

Almost done! The state_id value won't save unless you permit it in the Address controller. Go to the Address controller in app/controllers/addresses_controller.rb and add the properties to permit in the address_params method at the bottom.

def address_params
  params.require(:address).permit(:state_id)
end

Now you should be able to save and update Addresses with their associated State via the state_id column.


Advertisement

One Comment

Name
A name is required.
Email
An email is required.
Site
Invalid URL