使用上下文

时间:2015-11-25 10:20:09

标签: ruby-on-rails ruby-on-rails-4 ruby-on-rails-4.2 named-scope scopes

我有4个型号:Artists, Editions, Events & EventItems

  • 版本有很多活动
  • 活动有许多艺术家通过EventItems
  • 版本有许多艺术家通过活动

对于艺术家,我有一个范围published

我将“活动”定义为处于状态为非draft的事件的艺术家。

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

这种方法很好,直到我开始链接它们,并希望艺术家至少参加特定版本published的活动。

Edition.first.artists.published

除了它还会在当前版本之外加入events并错误地发布艺术家(如果他们有任何已发布的事件(即使他们不在此特定版本中))之外,这是有效的。

为了让它正常工作,我必须像这样破解它(这太可怕了):

  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)

有没有提供更多范围的上下文,只包括这个版本中的那些事件?那么它的范围会正确吗?

谢谢!

1 个答案:

答案 0 :(得分:3)

恕我直言,问题依赖于您的关联和您正在生成的SQL,而不是您应该如何为范围提供上下文(传递参数是完全合法的)。

致电Event.artists时,您已经加入了has_many :artists, through: :events的活动以及加入events的不加区别的活动。最重要的是,你依靠事件来确定艺术家是否活跃,如果不是SRP违规,这是另一个混​​乱的来源。

我认为解决方案来自于定义正确的关联:

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

我不是100%确定宏选项,但你明白了。