Search code examples
ruby-on-railsassociations

Can't access User's Role with has_one association


I have a User table which has a reference on a Role model. I want a User to have only one Role so I set up a has_one association in my User model like this:

has_one :role

And this is my Role model association:

belongs_to :user

This is what I have in my schema.rb for user table:

# other stuff
t.bigint "role_id"
t.index ["role_id"], name: "index_users_on_role_id"

I think I planned out my role system poorly but I am trying to save it. I want to access the user's role by using user.role with user being an instance of the User model.

Why is it when I call user.role I get an error saying: ActiveRecord::StatementInvalid (PG::UndefinedColumn: ERROR: column roles.user_id does not exist) LINE 1: SELECT "roles".* FROM "roles" WHERE "roles"."user_id" = $1 L...

UPDATE
Migration file for creating Role table:

class CreateRoles < ActiveRecord::Migration[6.0]
  def change
    create_table :roles do |t|
      t.string :name, null: false, default: ""
      t.boolean :can_delete_any_job, null: false, default: false
      t.boolean :can_kick_any_user, null: false, default: false
      t.boolean :can_claim_any_application, null: false, default: false
      t.boolean :can_create_events, null: false, default: false
      t.boolean :can_create_news_announcement, null: false, default: false
      t.timestamps
    end
  end
end

Solution

  • You need to have a column named user_id on the roles table. You can create a new migration to solve this.

    rails g migration add_missing_columns
    
    # in the migration
    add_column :roles, :user_id, :integer
    remove_column :users, :role_id
    
    # then in console
    rails db:migrate
    

    Ideally however you would want a join table with something like

    create_table :roles_users do |t|
      t.references :user
      t.references :role
    end
    

    and then

    class User < ApplicationRecord
      has_many :roles_users
      has_many :roles, through: :roles_users
    end
    
    class Role < ApplicationRecord
      has_many :roles_users
      has_many :users, through: :roles_users
    end
    
    class RolesUser < ApplicationRecord
      belongs_to :user
      belongs_to :role
    end