Использование области действия в ассоциации

Итак, я получил эту сумасшедшую идею, что я хотел применить область для включенной ассоциации. Это то, что я понял, и, похоже, все прекрасно:

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, если это возможно. Любые идеи для этого?

Ответ 1

Этот код кажется слишком сложным. Предполагая, что ваша цель состоит в том, чтобы получить все события, которые содержат гонки только с "медалями" для призов, не будет простой работой 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, чтобы получить плохие расы.

Ответ 2

Более актуальным способом выражения области вашей ассоциации является следующее:

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

Ответ 3

Вы можете использовать области действия на обеих моделях с помощью метода 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