Rails Migration: add_reference to Table but Different Column Name For Foreign Key Than Rails Convention

in rails 5.x you can add a foreign key to a table with a different name like this:

class AddFooBarStoreToPeople < ActiveRecord::Migration[5.0]
  def change
    add_reference :people, :foo_bar_store, foreign_key: { to_table: :stores }
  end
end

In Rails 4.2, you can also set up the model or migration with a custom foreign key name. In your example, the migration would be:

class AddReferencesToPeople < ActiveRecord::Migration
  def change
    add_column :people, :foo_bar_store_id, :integer, index: true
    add_foreign_key :people, :stores, column: :foo_bar_store_id
  end
end

Here is an interesting blog post on this topic. Here is the semi-cryptic section in the Rails Guides. The blog post definitely helped me.

As for associations, explicitly state the foreign key or class name like this (I think your original associations were switched as the 'belongs_to' goes in the class with the foreign key):

class Store < ActiveRecord::Base
  has_one :person, foreign_key: :foo_bar_store_id
end

class Person < ActiveRecord::Base
  belongs_to :foo_bar_store, class_name: 'Store'
end

Note that the class_name item must be a string. The foreign_key item can be either a string or symbol. This essentially allows you to access the nifty ActiveRecord shortcuts with your semantically-named associations, like so:

person = Person.first
person.foo_bar_store
# returns the instance of store equal to person's foo_bar_store_id

See more about the association options in the documentation for belongs_to and has_one.


EDIT: For those that see the tick and don't continue reading!

While this answer achieves the goal of having an unconventional foreign key column name, with indexing, it does not add a fk constraint to the database. See the other answers for more appropriate solutions using add_foreign_key and/or 'add_reference'.

Note: ALWAYS look at the other answers, the accepted one is not always the best!

Original answer:

In your AddReferencesToPeople migration you can manually add the field and index using:

add_column :people, :foo_bar_store_id, :integer
add_index :people, :foo_bar_store_id

And then let your model know the foreign key like so:

class Person < ActiveRecord::Base
  has_one :store, foreign_key: 'foo_bar_store_id'
end