205

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!

iGEL
  • 16,540
  • 11
  • 60
  • 74
stackOverlord
  • 5,342
  • 6
  • 28
  • 29

3 Answers3

211

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.

Gautam Chibde
  • 1,167
  • 3
  • 14
  • 27
Jon M.
  • 3,483
  • 1
  • 20
  • 18
  • 1
    Is it possible to generate a model with references of two tables – praveenkumar Dec 08 '16 at 06:41
  • Note that it does not add a has_many association on the other model (user), which you may want to add as well. – Sv1 Jun 27 '19 at 21:50
  • I think using `:references` will create an index on the foreign key, whereas manually making the column will not? – stevec Dec 13 '20 at 13:54
61

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

Gautam Chibde
  • 1,167
  • 3
  • 14
  • 27
Shiva
  • 11,485
  • 2
  • 67
  • 84
  • 3
    It seems that latest Rails generator replaced the `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. – Franklin Yu Sep 06 '16 at 22:36
  • Oh, the [`add_reference` action](http://api.rubyonrails.org/v5.0.0/classes/ActiveRecord/ConnectionAdapters/SchemaStatements.html#method-i-add_reference) has a `:foreign_key` option which *add an appropriate foreign key constraint*. I guess this option would do the same when creating table. – Franklin Yu Sep 06 '16 at 22:52
  • How do you export your ruby db to workbench? could you maybe answer this here: http://stackoverflow.com/questions/42982921/exporting-a-ruby-on-rails-sql-db-to-mysql-workbench – Krawalla Mar 23 '17 at 18:04
  • Does having `add_foreign_key :microposts, :users ` make any difference for Rails? – Linus Jul 16 '18 at 09:02
17

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`
Krule
  • 6,468
  • 3
  • 34
  • 56
  • 1
    can you explain what do you mean by saying that references will not create foreign keys for you. How is it different from first command using user_id:integer directly? – shailesh Jul 22 '12 at 04:08
  • It isn't, except in case you are using `:polymorphic` option (which IMHO, for most cases, is not a good idea). If you want to utilize foreign keys in ActiveRecord, use [foreigner](https://github.com/matthuhiggins/foreigner). – Krule Jul 23 '12 at 08:56
  • 1
    @Krule Now `add_foreign_key` has made it into ActiveRecord. – Franklin Yu Sep 06 '16 at 22:39