I have a model called Organization
that has many teams
and has many collaborations
. A Collaboration
also has many teams
. So the team model has a polymorphic association with Organization
and Collaboration
.
What I would like to do is organization.teams
and have that reflect all teams from the organization and all teams from the collaborations a part of the organization.
Tables
*organizations*
id
user_id
title
...
*collaborations*
id
organization_id
title
...
*teams*
id
teamable_id
teamable_type
title
...
Models
class Organization < ApplicationRecord
has_many :orgaization_teams, as: :teamable, class_name: "Team"
has_many :collaboration_teams, through: :collaborations, source: :teams, class_name: "Team"
end
class Collaboration < ApplicationRecord
belongs_to :organization
has_many :teams, as: :teamable
end
class Team < ApplicationRecord
belongs_to :teamable, polymorphic: true
belongs_to :organization, -> { joins(:teams).where(teams: {teamable_type: 'Organization'}) }, foreign_key: 'teamable_id'
belongs_to :collaboration, -> { joins(:teams).where(teams: {teamable_type: 'Collaboration'}) }, foreign_key: 'teamable_id'
end
Attempts
Attempt #1
class Organization < ApplicationRecord
has_many :teams, -> { joins(:organization, :collaboration) }, source: :teamable
end
Result: SystemStackError (stack level too deep)
Attempt #2
class Organization < ApplicationRecord
def teams
orgaization_teams.or(collaboration_teams)
end
end
Result: ArgumentError (Relation passed to #or must be structurally compatible. Incompatible values: [:joins])
Potential Solution
I'm considering separating the polymorphic association on Team to organization_id
and collaboration_id
So the new table would look like this:
*teams*
id
organization_id
collaboration_id
title
...
I would go with two seperate foreign keys instead:
class Organization < ApplicationRecord
has_many :teams
has_many :collaborations
has_many :collaboration_teams,
through: :collaborations,
source: :team
end
class Collaboration < ApplicationRecord
belongs_to :organization
has_many :teams
end
class Team < ApplicationRecord
belongs_to :team, optional: true
belongs_to :organization, optional: true
end
If you want to get teams that directly belong to an or org or a its collaborations you want:
Team.where(
organization_id: org.id
).or(
Team.where(
collaboration_id: org.collaborations
)
)
I don't think this can actually be written as an association as its too structurally complex.