Rails 4 Migration | Add Table with Reference

20,528

Solution 1

This part of your migration:

t.references :collaborator, index: true, foreign_key: true

will try to create a foreign key inside the database so that the collaborator_id column of the collaborations table will be guaranteed to be NULL or contain the id of a column in the collaborators table. You can't create that FK until the collaborators table exists.

The error you're getting is:

relation "collaborators" does not exist

and that's just telling you that you don't have a collaborators table but you're trying to reference it.

You need a migration to create the collaborators table before you create your collaborations table.

Solution 2

In Rails 5, at least, you can use foreign_key: {to_table: ... }} as follows.

create_table :messages, id: :uuid do |t|
  t.references :from_user, type: :uuid, index: true, null: false, foreign_key: {to_table: :users, on_delete: :cascade}
  t.references :to_user, type: :uuid, references: :user, index: true, null: false, foreign_key: {to_table: :users, on_delete: :cascade}
  t.text :body, null: false
  t.timestamps
end

Solution 3

sorry for being late, but essentially it's all about convenience, remember that's the essence of rails. so; every reference should be targeting the table that should be in the plural (since a table holds many "objects") therefore, you must make the reference to plural so rails will generate a reference to a singular object. button line, your migration should look more like;

class CreateCollaborations < ActiveRecord::Migration
  def change
    create_table :collaborations do |t|
        t.references :projects, index: true, foreign_key: true
        t.references :collaborators, index: true, foreign_key: true
        t.boolean :accepted

        t.timestamps null: false
    end
  end
end

Now, if you follow the conventions, then you should have no problem with the rest, just keep in mind that belong_to is to a singular object and has_many is to a plural object.

PS: I would not use past reference for the column, like accepted

Happy Coding

Share:
20,528
Michael Fich
Author by

Michael Fich

Updated on July 09, 2022

Comments

  • Michael Fich
    Michael Fich almost 2 years

    I am attempting to create a Collaboration table in my Rails 4 project, but I've run into an issue. I wish it to belong_to a single user, the collaborator.

    I ran the following command to generate the model and the migration, which I've also copied below.

    rails generate model Collaboration project:references collaborator:references accepted:boolean
    

    Migration:

    class CreateCollaborations < ActiveRecord::Migration
        def change
            create_table :collaborations do |t|
                t.references :project, index: true, foreign_key: true
                t.references :collaborator, index: true, foreign_key: true
                t.boolean :accepted
    
                t.timestamps null: false
            end
        end
    end
    

    Model:

    class Collaboration < ActiveRecord::Base
        belongs_to :project
        belongs_to :collaborator, class_name: 'User'
    end
    

    I updated the Collaboration model to include , class_name: 'User' as shown above. Similarly, I updated the existing Strategy model to include a has_many :collaborations

    class Project < ActiveRecord::Base
        has_many :collaborations
    end
    

    When I run rake db:migrate, I get the following error reported.

    rake aborted!
    StandardError: An error has occurred, this and all later migrations canceled:
    
    PG::UndefinedTable: ERROR:  relation "collaborators" does not exist
    

    I'm a bit puzzled as to wy this is happening. Any assistance would be greatly appreciated! Thank you. :)

    EDIT:

    Adding code for my User model as well.

    class User < ActiveRecord::Base
        authenticates_with_sorcery!
    
        has_many :projects
        has_many :collaborations
    end
    

    I edited out validations for fields such as password, email, etc to try to remove clutter.

  • MarsAtomic
    MarsAtomic over 8 years
    This is what I was thinking as well. Just to clarify, he's aliasing user as collaborator, so he needs to make sure his create_users_xxxxx.rb migration takes place before this create_collaborations_yyyyy.rb migration.
  • Michael Fich
    Michael Fich over 8 years
    Hmm, I have a users table which was set up earlier in my project. I tried to add a separate migration to add a collaborator reference to the collaborators table however I ran into the same error with that migration as I encountered with the first.
  • Michael Fich
    Michael Fich over 8 years
    @MarsAtomic - That's exactly right! The issue is because I am trying to reference the users table while aliasing it as "collaborator". Still working through the errors though.
  • mu is too short
    mu is too short over 8 years
    So collaborations.collaborator_id is supposed to be a users.id value? How do you feel about using t.references :user instead?
  • Michael Fich
    Michael Fich over 8 years
    @muistooshort - That's something I could look to use if I can't get this sorted out. I'd like to get it figured out as it's currently constructed first, if possible.
  • mu is too short
    mu is too short over 8 years
    As near as I can tell, you can (1) use user_id as the column name (i.e. t.references :user), (2) don't use an FK (i.e. foreign_key: false), or (3) add the database FK by hand with a bit of SQL. (1) is the most Railsy I suppose, (2) is a shortcut to broken data in your database, (3) will require switching your schema.rb to structure.sql. The docs don't seem to offer anything else. I do (3) because I use all kinds of things in the database that AR doesn't understand.