[ruby-on-rails] generate model using user:references vs user_id:integer

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 http://guides.rubyonrails.org/ 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!

This question is related to ruby-on-rails

The answer is


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.

FYI
Declaring the foreign keys using the former method only lets the Rails know about the relationship the models/tables have. The database is unknown about the relationship. Therefore when you generate the EER Diagrams using software like MySql Workbench you find that there is no relationship threads drawn between the models. Like in the following pic enter image description here

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

Now the foreign key is set at the database level. and you can generate proper EER diagrams. enter image description here


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`