Rails migration: t.references with alternative name?

87,180

Solution 1

I think this thread has a different more Rails-ish way: Scaffolding ActiveRecord: two columns of the same data type

In the migration:

t.belongs_to :transferrable_as

t.belongs_to :same_as

Solution 2

You can do this all in the initial migration/column definition (at least currently in Rails 5):

t.references :transferable_as, index: true, foreign_key: {to_table: :courses}
t.references :same_as, index: true, foreign_key: {to_table: :courses}

Solution 3

You can do it this way:

create_table :courses do |t|
  t.string :name
  t.references :transferrable_as
  t.references :same_as
  t.timestamps
end

or using t.belongs_to as an alias for t.references

You can't add foreign_key: true to those two references lines. If you want to mark them as foreign keys at the database level you need to have a migration with this:

add_foreign_key :courses, :courses, column: :transferrable_as_id
add_foreign_key :courses, :courses, column: :same_as_id

Update

In Rails 5.1 and above you can add the foreign key in the migration in the create_table block like this:

create_table :courses do |t|
  t.string :name
  t.references :transferrable_as, foreign_key: { to_table: 'courses' }
  t.references :same_as, foreign_key: { to_table: 'courses' }
  t.timestamps
end

Solution 4

As an added answer to this question -- the Model should have the following line to complete the association:

    belongs_to :transferrable_as, class_name: "Course"
    belongs_to :same_as, class_name: "Course"

Solution 5

I don't think references accepts the :as option, but you can create your columns manually...

create_table :courses do |t| 
  t.string  :name 
  t.integer :course1_id
  t.integer :course2_id 
  t.timestamps 
end 
Share:
87,180
themirror
Author by

themirror

Updated on July 08, 2022

Comments

  • themirror
    themirror almost 2 years

    So I have a create_table like this for Courses at a School:

    create_table :courses do |t|
      t.string :name
      t.references :course
      t.timestamps
    end
    

    but I want it to reference two other courses like:

    has_many :transferrable_as # A Course
    has_many :same_as          # Another Course
    

    Can I say the following?

    t.references :transferrable_as, :as=> :course
    
  • Toby 1 Kenobi
    Toby 1 Kenobi almost 9 years
    but how does the db know which foreign key to link the table to? I'm trying this with Postgres database and it's giving me an error PG::UndefinedTable: ERROR it's trying to add a foreign key constraint to a table that doesn't exist.
  • Matthew Clark
    Matthew Clark almost 9 years
    The part about not being able to add foreign_key: true to the references lines was what was tripping me up. Adding the add_foreign_key and specifying the column name for those did the trick.
  • Beni Cherniavsky-Paskin
    Beni Cherniavsky-Paskin about 8 years
    Does this work out of the box in Rails? According to stackoverflow.com/a/22384289/239657, this requires the schema_plus gem. Rails' add_reference docs don't mention a :references options.
  • Toby 1 Kenobi
    Toby 1 Kenobi about 8 years
    It works out of the box on Rails 4.2 in my experience. Interesting observation about that option nor being in the docs. Those docs also say that the :foreign_key option is available but I found it wasn't. Perhaps a different method gets called somehow.
  • MCB
    MCB over 7 years
    I'm not following what the references: option is for (as opposed to t.references wouldn't that only be relevant on the model level, with the foreign_key considerations being taken care of by add_foreign_key?
  • Toby 1 Kenobi
    Toby 1 Kenobi over 7 years
    @MCB t.references says "add a field to this table that is the primary key of another table." The references: option tells it which table it is a primary key of (needed if it is not clear by the name of the field). The add_foreign_key function tells the database to enforced referential integrity here.
  • MCB
    MCB over 7 years
    @Toby1Kenobi Ok, I ran them both and didn't notice any difference in my schema though
  • Toby 1 Kenobi
    Toby 1 Kenobi over 7 years
    @MCB you ran both what exactly?
  • MCB
    MCB over 7 years
    @Toby1Kenobi Oh, a migration each way, with a references: :user and I rolled it back and ran it again without that, and the schema looked the same both ways.
  • Toby 1 Kenobi
    Toby 1 Kenobi over 7 years
    @MCB what did you name the attribute?
  • MCB
    MCB over 7 years
    @Toby1Kenobi the line was t.belongs_to :vendor and a vendor is a user
  • Toby 1 Kenobi
    Toby 1 Kenobi over 7 years
    @MCB oh, well I suppose ActiveRecord doesn't need to know what table it's referencing to make a foreign key, if all primary keys are the same type (integer), but it makes me feel better if it does have access to that info. What if in the future it supports a database back end where the primary key can be a variety of different types? Then the references: option would be needed.
  • MCB
    MCB over 7 years
    No idea, never handled that situation before, and honestly only have really dealt with a db through AR except when issues were dire. But as far as I know this is all handled at the model level and migrations just handle setting up the DB. Would postgresql ever need this info or just for writing sql?
  • stephenmurdoch
    stephenmurdoch about 7 years
    This works on Rails 5.1 and none of the other suggestions do. It's much cleaner, and feels right.
  • Quv
    Quv over 6 years
    I use Rails 5.1.4 but it doesn't work. When I specify a foreign_key option in the table creation like this ways, it raises an error saying the very table I'm creating doesn't exist... So I suspect it's not really supported by the official API.
  • Jonathan Reyes
    Jonathan Reyes about 6 years
    I also read that index is already added to foreign keys as of Rails stackoverflow.com/questions/39769981/…
  • Toby 1 Kenobi
    Toby 1 Kenobi almost 6 years
    @MCB after all this time I realise you were right all along. Your first comment above is exactly right - the add_foreign_key lines take care of informing the database what is a foreign key of what. The references: parameter is doing nothing.
  • Jason Swett
    Jason Swett over 5 years
    In case anyone is wondering, belongs_to is just an alias to references and so has the exact same functionality.
  • Serge Vinogradov
    Serge Vinogradov about 3 years
    from what I've seen, passing index:true is redundant, t.references :transferable_as, foreign_key: {to_table: :courses} also creates index.