ChatGPT解决这个技术问题 Extra ChatGPT

Generate model in Rails using user_id:integer vs user:references

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!


G
Gautam Chibde

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.


Is it possible to generate a model with references of two tables
Note that it does not add a has_many association on the other model (user), which you may want to add as well.
I think using :references will create an index on the foreign key, whereas manually making the column will not?
G
Gautam Chibde

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


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.
Oh, the 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.
How do you export your ruby db to workbench? could you maybe answer this here: stackoverflow.com/questions/42982921/…
Does having add_foreign_key :microposts, :users make any difference for Rails?
K
Krule

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`

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?
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.
@Krule Now add_foreign_key has made it into ActiveRecord.