r00k
r00k

Reputation: 661

What's the best way to define a scope inside of a module in Rails 3?

I have a number of models that need the same scope. They each have an expiration_date date field that I want to write a scope against.

To keep things DRY, I'd like to put the scope in a module (in /lib) that I'll extend each model with. However, when I call scope within the module, the method is undefined.

To work around this, I use class_eval when the module is included:

module ExpiresWithinScope
  def self.extended(base)
    scope_code = %q{scope :expires_within, lambda { |number_of_months_from_now| where("expiration_date BETWEEN ? AND ?", Date.today, Date.today + number_of_months_from_now) } }
    base.class_eval(scope_code)
  end 
end

I then do extend ExpiresWithinScope in my models.

This approach works, but feels a little hackish. Is there a better way?

Upvotes: 3

Views: 2489

Answers (2)

BaroqueBobcat
BaroqueBobcat

Reputation: 10150

You could do something a little cleaner like this, since scope is a public class method:

module ExpiresWithinScope
  def self.included(base)
    base.scope :expires_within, lambda { |number_of_months_from_now| 
      base.where("expiration_date BETWEEN ? AND ?", 
        Date.today,
        Date.today + number_of_months_from_now) 
    }
  end 
end

and then in your model

include ExpiresWithinScope

Upvotes: 10

Reactormonk
Reactormonk

Reputation: 21700

With AR3, they finally got somewhere near DataMapper awesomeness, so you can go

module ExpiresWithinScope
  def expires_within(months_from_now)
    where("expiration_date BETWEEN ? AND ?", 
    Date.today,
    Date.today + number_of_months_from_now) 
  end
end

You could also try:

module ExpiresWithinScope
  def expires_within(months_from_now)
    where(:expiration_date => Date.today..(Date.today + number_of_months_from_now))
  end
end

But according to the guide, arel can't handle that as well.

Upvotes: 5

Related Questions