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