在关联上使用范围

时间:2011-02-01 05:04:24

标签: ruby-on-rails-3 activerecord arel

所以我有一个疯狂的想法,我想将一个范围应用于一个包含的协会。这就是我想到的,它似乎工作正常:

class Event < ActiveRecord::Base
  has_many :races
  has_many :bad_races, :conditions => Race.bad_medals_sql, :class_name => "Race"
end

class Race < ActiveRecord::Base
  def self.bad_medals_sql
    arel_table[:prizes].eq('medals').to_sql
    # This returns a string
    # "`races`.`prizes` = 'medals'"
  end

  def self.bad_medals
    where(bad_medals_sql)
  end
end

Event.includes(:bad_races)
Reloading...
  Event Load (0.4ms)  SELECT `events`.* FROM `events`
  Race Load (0.5ms)  SELECT `races`.* FROM `races` WHERE (`races`.event_id IN (1,2,3,4) AND (`races`.`prizes` = 'medals'))

问题在于它真的很钝。为了在Race上定义范围(在别处使用)并在Event的关联上使用它,我必须在Race上有两个方法。对于每个范围。

我确信我可以将模式包装成插件或其他一些插件,但如果可能的话,我宁愿使用原生AR / ARel。有没有这样做的想法?

3 个答案:

答案 0 :(得分:6)

这段代码看起来过于复杂。假设您的目标是让所有包含仅有“奖牌”的比赛的活动用于奖品,那么简单的scope是否有效?

class Event < ActiveRecord::Base
  has_many :races
  scope :bad_races, includes(:races).where("races.prizes=?", "medals")
end

class Race < ActiveRecord::Base
  belongs_to :event
end

然后你可以运行Event.bad_races来获得糟糕的比赛。

答案 1 :(得分:0)

表达关联范围的最新方式如下:

scope :bad_races, -> { joins(:races).where(races: { prizes: 'medals' }) }

答案 2 :(得分:0)

您可以使用merge方法在两个模型上使用范围。在这种情况下它非常方便:

class Event < ActiveRecord::Base
  has_many :races
  scope :bad_races, -> { joins(:races).merge(Race.bad_medals) }
end

class Race < ActiveRecord::Base
  belongs_to :event
  scope :bad_medals, -> { where(price: 'medal') }
end