Rails 3 migrations: Adding reference column?
Asked Answered
E

10

162

If I create a new rails 3 migration with (for example)

rails g migration tester title:tester user:references

, everything works fine...however if I add a column with something along the lines of:

rails g migration add_user_to_tester user:references

the reference field is not recognised. In short, the question is: how do I add a referencing column to a rails migration from the command line?

Epileptic answered 10/2, 2011 at 8:46 Comment(0)
S
205

If you are using the Rails 4.x you can now generate migrations with references, like this:

rails generate migration AddUserRefToProducts user:references

like you can see on rails guides

Submultiple answered 3/5, 2013 at 8:43 Comment(5)
See section 2.1 from edgeguides.rubyonrails.org/active_record_migrations.html for example.Respire
how do you specify a column name for the foreign key instead the auto generated name?Dollhouse
@jwill you can use polymorphic: user:references{polymorphic}.Submultiple
@PauloFidalgo Can you explain a bit about how to do that? may be some guide of links? (talking about polymorphic)Experiment
@Anwar: here are the docs api.rubyonrails.org/classes/ActiveRecord/ConnectionAdapters/…Submultiple
C
186

EDIT: This is an outdated answer and should not be applied for Rails 4.x+

You don't need to add references when you can use an integer id to your referenced class.

I'd say the advantage of using references instead of a plain integer is that the model will be predefined with belongs_to and since the model is already created and will not be affected when you migrate something existing, the purpose is kind of lost.

So I would do like this instead:

rails g migration add_user_id_to_tester user_id:integer

And then manually add belongs_to :user in the Tester model

Cismontane answered 10/2, 2011 at 9:13 Comment(9)
But that won't create the appropriate foreign key constraints on databases that support it, right?Extravasate
No, afaik Rails never create foreign key restraints on the database unless you add plugins to do it for you.Cismontane
just studying this post, pls how do i add the reference after allBeastings
The way I showed does add a reference. But instead of it being a one line generator, it also requires you to add the reference code into your existing model, which is also included in the answerCismontane
remember to add the index with user:integer:indexHighbinder
This answer is really good, but I'm not sure I understand it fully due to the confusing grammar (multiple 'and' and 'since'. not sure where sentences end and start.) "the model will be predefined with belongs_to and since the model is already created and will not be affected when you migrate something existing, the purpose is kind of lost."Initiation
What should i do if the user model is like, Subscription::User so how will i write the migration for this?Expressway
Answer is dated, see @Paulo's answer for modern rails.Ulises
@Extravasate with Rails > 4.2 there is now an add_foreign_key method which facilitates adding a fk constraint at the db levelGasoline
S
103

Please note that you will most likely need an index on that column too.

class AddUserReferenceToTester < ActiveRecord::Migration
  def change
    add_column :testers, :user_id, :integer
    add_index  :testers, :user_id
  end
end
Sitting answered 5/1, 2012 at 2:33 Comment(3)
Why? Is this true for most belongs_to relationships?Initiation
It is indeed for performance reasons and comes in handy if you have a has_many/has_one on the other side of that belongs_to relation. If you are absolutely sure that you will not go through user.testers you can omit the index.Undersized
The rails g migration ... generated add_reference :installs, :device, index: true which also creates the index.Respire
O
49

With the two previous steps stated above, you're still missing the foreign key constraint. This should work:

  class AddUserReferenceToTester < ActiveRecord::Migration
      def change
          add_column :testers, :user_id, :integer, references: :users
      end
  end
Optimize answered 30/4, 2013 at 16:4 Comment(2)
This is the only actual answer here. The foreign key is the most critical part hereHalla
this should be marked as the correct answer since the questions asks for rails 3Supernatant
C
35

You can use references in a change migration. This is valid Rails 3.2.13 code:

class AddUserToTester < ActiveRecord::Migration
  def change
    change_table :testers do |t|
      t.references :user, index: true 
    end
  end
  def down
    change_table :testers do |t|
      t.remove :user_id
    end
  end
end

c.f.: http://apidock.com/rails/ActiveRecord/ConnectionAdapters/SchemaStatements/change_table

Chiliasm answered 26/6, 2013 at 8:40 Comment(3)
change and down methods? aren't up and down methods instead?Potash
@Potash yes, and you can also just leave off the down method.Raster
@Potash Without the down method, I got ActiveRecord::IrreversibleMigration when rolling back using Rails 3.2. I also had to change change to up.Cooley
B
27

Running rails g migration AddUserRefToSponsors user:references will generate the following migration:

def change
  add_reference :sponsors, :user, index: true
end
Bimolecular answered 21/7, 2014 at 20:42 Comment(1)
Which version of Rails is this for?Cooley
S
8

When adding a column you need to make that column an integer and if possible stick with rails conventions. So for your case I am assuming you already have a Tester and User models, and testers and users tables.

To add the foreign key you need to create an integer column with the name user_id (convention):

add_column :tester, :user_id, :integer

Then add a belongs_to to the tester model:

class Tester < ActiveRecord::Base
  belongs_to :user
end

And you might also want to add an index for the foreign key (this is something the references already does for you):

add_index :tester, :user_id
Stereochrome answered 3/9, 2012 at 12:58 Comment(0)
D
8

That will do the trick:

rails g migration add_user_to_tester user_id:integer:index
Devonne answered 3/7, 2013 at 10:6 Comment(1)
I like that this also adds the index that you will most likely want.Bael
O
3

You can add references to your model through command line in the following manner:

rails g migration add_column_to_tester user_id:integer

This will generate a migration file like :

class AddColumnToTesters < ActiveRecord::Migration
  def change
    add_column :testers, :user_id, :integer
  end
end

This works fine every time i use it..

Omnirange answered 29/5, 2013 at 8:47 Comment(0)
C
3

For Rails 4

The generator accepts column type as references (also available as belongs_to).

This migration will create a user_id column and appropriate index:

$ rails g migration AddUserRefToProducts user:references 

generates:

class AddUserRefToProducts < ActiveRecord::Migration
  def change
    add_reference :products, :user, index: true
  end
end

http://guides.rubyonrails.org/active_record_migrations.html#creating-a-standalone-migration

For Rails 3

Helper is called references (also available as belongs_to).

This migration will create a category_id column of the appropriate type. Note that you pass the model name, not the column name. Active Record adds the _id for you.

change_table :products do |t|
  t.references :category
end

If you have polymorphic belongs_to associations then references will add both of the columns required:

change_table :products do |t|
  t.references :attachment, :polymorphic => {:default => 'Photo'}
end

Will add an attachment_id column and a string attachment_type column with a default value of Photo.

http://guides.rubyonrails.org/v3.2.21/migrations.html#creating-a-standalone-migration

Clink answered 13/10, 2015 at 10:58 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.