Reputation:
I'm quite new to rails and have been trying to work this out all night with no luck.
I have created 3 models: users
, businesses
, and business_hours
. I have also added the associations (business_hours belongs_to businesses which belongs_to users
) and (user has_one business which has_many business_hours
).
Reading through the docs online it seems I now need to create the foreign keys for these relationships in my DB tables. How do I do this using Rails ActiveRecord migrations? I'm using PostgreSQL as my DB.
Upvotes: 49
Views: 94746
Reputation: 455
Rails 5 now can add foreign key in migrations, see http://devdocs.io/rails~5.0/activerecord/connectionadapters/schemastatements#method-i-add_foreign_key. So
add_foreign_key :articles, :authors
creates
ALTER TABLE "articles" ADD CONSTRAINT fk_rails_e74ce85cbc FOREIGN KEY ("author_id") REFERENCES "authors" ("id")
If you have a non standard data model you can do.
add_foreign_key :articles, :users, column: :author_id, primary_key: "lng_id"
which creates
ALTER TABLE "articles" ADD CONSTRAINT fk_rails_58ca3d3a82 FOREIGN KEY ("author_id") REFERENCES "users" ("lng_id")
Upvotes: 13
Reputation: 30453
First of all when you use belongs_to method don't use s
at the end of the word: business_hours belongs_to business which belongs_to user
.
Now create a migration:
rails generate migration migration_name
And in migration add columns:
class MigrationName < ActiveRecord::Migration
def change
add_foreign_key :business_hours, :businesses
add_foreign_key :businesses, :users
end
end
Run rake db:migrate
. That's it.
Upvotes: 35
Reputation: 2597
The currently accepted answer on this isn't really accurate as it doesn't add a database foreign key. It's just adding integer columns.
In Rails 4.2.x, the current approach is:
http://guides.rubyonrails.org/active_record_migrations.html#foreign-keys
Create a migration:
rails generate migration migration_name
For existing columns, in the migration add the foreign keys like this:
class MigrationName < ActiveRecord::Migration
def change
add_foreign_key :business_hours, :businesses
add_foreign_key :businesses, :users
end
end
For Rails 4.x or if you're adding a new column and want it to be a foreign key you can do this, where you probably also want to specify the index as true, but that's not part of the requirement for the foreign key:
http://edgeguides.rubyonrails.org/active_record_migrations.html#creating-a-migration
class MigrationName < ActiveRecord::Migration
def change
add_reference :business_hours, :business, index: true, foreign_key: true
add_reference :businesses, :user, index: true, foreign_key: true
end
end
Upvotes: 79
Reputation: 5649
I haven't tried it with PostgreSQL but at least with MySQL Rails do NOT create foreign keys, I mean not real db-level foreign keys. All they create is an integer that is named according to the convention. That means that out of the box you do not get the index on this fake foreign key(for faster lookup) and there is also no db-level referential integrity check. To get that you need to do something like:
ALTER TABLE your_table ADD CONSTRAINT fk_whatever_you_want_to_name_it FOREIGN KEY (foreign_key_name) REFERENCES another_table(its_primary_key)
In a Rails migration you can pass this as a string argument to the "execute" function. Adding a "real" foreign key also automatically creates an index. At least for me this was a rather nasty surprise.
Upvotes: 6