简体   繁体   中英

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?

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

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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM