4

I have 4 models: Artists, Editions, Events & EventItems.

  • Editions have many Events
  • Events have many Artists through EventItems
  • Editions have many Artists through Events

On artists I have a scope published

I define active as an artists who is on an event which has a state which is NOT draft.

scope :published, -> { joins(:events).where("events.state != ?", 'draft').uniq }

This works fine until I start chaining them and want Artists who have at least on event which is published for a given edition.

Edition.first.artists.published

This works except that it will also joins events outside the current edition and wrongly publish artists if they have any events published (even if they are not in this particular edition).

To get it to work properly I had to hack it like so (which is horrible):

  scope :published, ->(edition = nil) {
    if edition.present?
      joins(:events).where("events.state != ? AND events.edition_id = ?", 'draft', edition.id).uniq
    else
      joins(:events).where("events.state != ?", 'draft').uniq
    end
  }

Edition.first.artists.published(Edition.first)

Is there anyway to give more context to the scope to only include those events in this edition? So it will scope correctly?

Thanks!

ere
  • 1,739
  • 3
  • 19
  • 41

1 Answers1

3

IMHO the problem relies on your associations and the SQL you're generating, not how you should provide context to a scope (passing an argument is perfectly legitimate).

When calling Event.artists you're already joining events with has_many :artists, through: :events and by that joining events indiscriminately. On top of that you are relying on events to determine if artists are active or not which is another source of confusion if not SRP violation.

I think the solution comes from defining the right associations :

class Edition
  has_many :events
  has_many :artists, through: :events

  has_many :active_events, -> {where.not(state: "draft")}, class_name: "Events"
  has_many :active_artists, through: :active_events, 
            class_name: "Artist", 
            source: :artists # => not sure if this option is necessary
end

class Events
  has_many :event_items
  has_many :artists, through: :event_items
end 

Event.first.active_artists

I am not 100% sure about the macros options but you get the idea.

charlysisto
  • 3,700
  • 17
  • 30