eclectic923
eclectic923

Reputation: 2204

why doesn't has_many :through work here...is there a hidden limitation?

This question is for Rails 3.0.0.

I have 5 tables (contrived but reasonable example, only 4 matter):

capabilities
    id
    name

capability_roles
    role_id
    capability_id

user_roles
    user_id
    role_id

users
    id
    name

roles
    id
    name

Basically capabilities connects to roles_capabilities connects to user_roles connects to users.

The *_roles tables are simply maps. They have no primary key. The roles table itself is almost incidental to this question.

This allows the capabilities of each role be edited independently of the roles users are allowed to assume.

It would be nice to simply figure out which capabilities a user has.

Now set up associations:

users
    has_many :user_roles  # .joins( :user_roles ).to_sql # works

user_roles
    belongs_to :user # .joins( :user ).to_sql # works

    # .joins( :capability_roles ).to_sql # works (no corresponding belongs_to!)
    has_many :capability_roles, :primary_key => role_id, :foreign_key => :role_id

    # .joins( :capabilities ).to_sql # fails
    has_many :capabilities, :through => :capability_roles

capability_roles
    belongs_to :capabilities # .joins( :capabilities ).to_sql # works

    # .joins( :user_roles ).to_sql # works (no corresponding belongs_to!)
    has_many :user_roles, :primary_key => role_id, :foreign_key => :role_id

    # .joins( :users ).to_sql # fails
    has_many :users, :through => :user_roles 

capabilities
    has_many :capability_roles  # .joins( :capability_roles ).to_sql # works

My question is:

Why doesn't has_many :through work here?

It seems like what has_many :through was designed for. I'm not sure if the missing/irrelevant belongs_to()'s are an issue.

The failure I see is: NoMethodError: undefined method `eq' for nil:NilClass

Upvotes: 2

Views: 379

Answers (1)

Jeremy Weathers
Jeremy Weathers

Reputation: 2554

The join tables you are using are designed for has_and_belongs_to_many relationships, not has_many, and are not expected to have associated classes. I'd go with something like this:

Role
  has_and_belongs_to_many :capabilities
  has_and_belongs_to_many :users

User
  has_and_belongs_to_many :roles
  has_many :capabilities # use SQL with sub-select through roles to get the capabilities

Capability
  has_and_belongs_to_many :roles
  has_many :users # use SQL with sub-select through roles to get the users

Upvotes: 2

Related Questions