1

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
...
Asdrubal
  • 2,421
  • 4
  • 29
  • 37

1 Answers1

1

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.

max
  • 96,212
  • 14
  • 104
  • 165