Suppose I have the following model, which defines a named_scope that filters out some instances based on the current time:
class Post < ActiveRecord::Base named_scope :current, lambda { { :conditions => ['do_not_show_before < ?', Time.now] } } end
I've been trying to come up with a good strategy for testing this, since the test depends on time of execution. If I were using a conventional method, say:
def self.current find :all, :conditions => ['do_not_show_before < ?', Time.now] end
I would simply rewrite it like this:
def self.current(time = Time.now) find :all, :conditions => ['do_not_show_before < ?', time] end
and then only pass in a time parameter during testing. But I don't know how to do with with named scopes because I cannot have optional arguments to a block.
For right now I've compromised by making a required time parameter as follows:
class Post < ActiveRecord::Base named_scope :current, lambda { |time| { :conditions => ['do_not_show_before < ?', time] } } end
This means that every time I use the named_scope I have to call it like this:
Post.current(Time.now).
I really don't like this, but it does facilitate testing, which I accomplish (using shoulda and factory_girl) thus:
context 'An embargoed post' do setup do @now = Time.now @post = Factory(:post, :no_not_show_before => @now) end
should 'be in the named_scope "current" after the do_not_show_before datetime' do assert_contains Post.current(@now + 1.second), @post end
should 'not be in the named_scope "current" before the embargoed_until datetime' do assert_does_not_contain Post.current(@now - 1.second), @post end end
Is there a better way to accomplish this using named_scopes?
-Sven