Search code examples
ruby-on-railsrelationshipnested-attributeshas-many-throughhas-and-belongs-to-many

multiple has_many through with the same model rails


I am trying to set up the model structure that has a User model Project model along with two join tables setup as has_many through to manage two specific aspects of the Project, ProjectManagers and ProjectMembers.

I can setup two has_and_belongs_to_many but it doesn't feel very railsy.

Right now, this is what I have and I'm unsure of how to proceed to use multiple has_many through (Project Manager, Project Member) both referencing User model.

Would a nested through be the way to go even if a Project Manager will not always be part of the Project User table?

project.rb

class Project < ApplicationRecord
  has_many :project_members
  has_many :users, through: :project_manager
end

user.rb

class User < ApplicationRecord
  has_many :project_managers
  has_many :users, through: :project_managers
end

project_manager.rb

class ProjectManager < ApplicationRecord
    belongs_to :project
    belongs_to :user
end

project_member.rb

class ProjectMember < ApplicationRecord
  belongs_to :project
  belongs_to :user
end

Solution

  • I don't see any problems with what you're doing. There are other options, but this approach should work as you want. Have you tried it? I'd do something like this.

    class Project < ApplicationRecord
      has_many :project_members
      has_many :project_managers
    
      has_many :members, through: :project_members, :class_name => User.to_s
      has_many :managers, through: :project_manager, :class_name => User.to_s
    end
    

    Another approach, since the join tables are similar is to subclass them and add a type column to the join table. Not necessarily better than what you're doing.

    You could also create a project_users table (don't separate members and managers) and include a "role" column. A scope on project_user.rb would bring back managers or members.

    Personally, I would go with your approach. Managers will likely have different auth and have relationships with other objects. It's simpler to query and less likely to make a mistake.

    And, I wouldn't recommend a has_and_belongs_to_many, you're likely to add other columns to the join table and you'll be glad you have the model.