using scope on an association

jsharpe picture jsharpe · Feb 1, 2011 · Viewed 15.1k times · Source

So I got this crazy idea that I wanted to apply a scope to an included association. This is what I figured out, and it seems to work just fine:

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'))

The problem is that it's really obtuse. In order to have the scope defined on Race (to use elsewhere) and to use it on the Event's association I have to have two methods on Race. For each scope.

I'm sure that I could wrap the pattern into a plugin or some such, but I'd much rather use native AR/ARel if that's possible. Any ideas for doing that?

Answer

Dylan Markow picture Dylan Markow · Feb 1, 2011

This code seems overly complex. Assuming that your goal is to get all the events that contain races with only "medals" for prizes, wouldn't a simple scope work?

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

Then you can just run Event.bad_races to get the bad races.