I'm confused on how to generate a model that belongs_to another model. My book uses this syntax to associate Micropost with User:
rails generate model Micropost user_id:integer
but https://guides.rubyonrails.org/active_record_migrations.html#creating-a-standalone-migration says to do it like this:
rails generate model Micropost user:references
The migrations generated by these 2 are different. Also, for the former, how does rails know that user_id
is a foreign key referencing user
? Thanks!
Both will generate the same columns when you run the migration. In rails console, you can see that this is the case:
:001 > Micropost
=> Micropost(id: integer, user_id: integer, created_at: datetime, updated_at: datetime)
The second command adds a belongs_to :user
relationship in your Micropost model whereas the first does not. When this relationship is specified, ActiveRecord will assume that the foreign key is kept in the user_id
column and it will use a model named User
to instantiate the specific user.
The second command also adds an index on the new user_id
column.
how does rails know that user_id is a foreign key referencing user?
Rails itself does not know that user_id
is a foreign key referencing user
. In the first command rails generate model Micropost user_id:integer
it only adds a column user_id
however rails does not know the use of the col. You need to manually put the line in the Micropost
model
class Micropost < ActiveRecord::Base
belongs_to :user
end
class User < ActiveRecord::Base
has_many :microposts
end
the keywords belongs_to
and has_many
determine the relationship between these models and declare user_id
as a foreign key to User
model.
The later command rails generate model Micropost user:references
adds the line belongs_to :user
in the Micropost
model and hereby declares as a foreign key.
https://i.stack.imgur.com/y6J0P.png
However, if you use the later method you find that you migration file looks like:
def change
create_table :microposts do |t|
t.references :user, index: true
t.timestamps null: false
end
add_foreign_key :microposts, :users
https://i.stack.imgur.com/ew9UO.png
add_foreign_key
action with an option foreign_key: true
to the t.references
line, which implies index: true
. So it is now t.references :user, foreign_key: true
. There is currently no documentation for the foreign_key
option available, so this is only my assumption.
add_reference
action has a :foreign_key
option which add an appropriate foreign key constraint. I guess this option would do the same when creating table.
add_foreign_key :microposts, :users
make any difference for Rails?
For the former, convention over configuration. Rails default when you reference another table with
belongs_to :something
is to look for something_id
.
references
, or belongs_to
is actually newer way of writing the former with few quirks.
Important is to remember that it will not create foreign keys for you. In order to do that, you need to set it up explicitly using either:
t.references :something, foreign_key: true
t.belongs_to :something_else, foreign_key: true
or (note the plural):
add_foreign_key :table_name, :somethings
add_foreign_key :table_name, :something_elses`
:polymorphic
option (which IMHO, for most cases, is not a good idea). If you want to utilize foreign keys in ActiveRecord, use foreigner.
add_foreign_key
has made it into ActiveRecord.
Success story sharing
:references
will create an index on the foreign key, whereas manually making the column will not?