Use a Custom Column Name With a belongs_to Association in Rails

Imagine an application with the following relationships:

  • A user model which has_many jobs through a jobs_project_managers join table.
  • A job model which has_many users through a jobs_project_managers join table.
  • A jobs_project_manager model connecting the job and user models.

Default Rails conventions would create a users method on a Job instance. However, there may be times when you want to customize the column name to be more expressive. In my case, I want a Job to have a project_managers method instead. This would still associate a job with a user model, but it reads better.

In order to achieve this, you’ll want to use the class_name and foreign_key options for the belongs_to method. Rails Guides provides an example of how to use these options. Essentially this allows you to create a custom name for the association, but tells Rails to refer to both the User class and the user_id column.

Before

Models

class User < ApplicationRecord
  has_many :jobs_project_managers, dependent: :destroy
  has_many :jobs, through: :jobs_project_managers
end
class Job < ApplicationRecord
  has_many :jobs_project_managers, dependent: :destroy
  has_many :users, through: :jobs_project_managers
end
class JobsProjectManager < ApplicationRecord
  belongs_to :user
  belongs_to :job
end

Factories

FactoryBot.define do
  factory :jobs_project_manager do
    user
    job
  end
end

After

Models

class User < ApplicationRecord
  has_many :jobs_project_managers, dependent: :destroy
  has_many :jobs, through: :jobs_project_managers
end
class Job < ApplicationRecord
  has_many :jobs_project_managers, dependent: :destroy
  has_many :project_managers, through: :jobs_project_managers
end
class JobsProjectManager < ApplicationRecord
  belongs_to :project_manager, class_name: "User", foreign_key: "user_id"
  belongs_to :job
end

Factories

FactoryBot.define do
  factory :jobs_project_manager do
    association :project_manager, factory: :user
    job
  end
end