petRUShka
petRUShka

Reputation: 10162

Rails: I want to stub Time.now but it won't be stubbed in scopes

I have such scope

  scope :old,   joins(:group).where("`users`.`created_at` <=
        DATE_SUB(?, INTERVAL `groups`.`check_minutes` MINUTE)", Time.now)

I stub Time.now as following

  Time.stub!(:now).and_return(Time.parse("1 JUL 2010"))

I want scope old to use this stubbed Time.now but it uses current time.

I suppose rails create scopes when load model first time (e.g. when load spec_helper.rb), so we stub Time.now after loading the scope. Is it true?

So I found two solutions:

  1. Reload User model after stubbing Time.now and before using scope
  2. Use regular method instead of stub like this

Do you have more elegant solutions?

Upvotes: 1

Views: 505

Answers (1)

Douglas F Shearer
Douglas F Shearer

Reputation: 26528

Having Time.now in a plain scope is undesirable, as you state the scope is setup when the model class is loaded, so a long running Rails process may have a scope that is from hours or days ago. The stubbing issue is a side-effect of this undesirable situation.

I would suggest you rewrite your scope using a lambda, so that Time.now is always queried. This will alleviate the stubbing issue and always get the latest Time.now.

scope :old,   lambda { joins(:group).where("`users`.`created_at` <=
        DATE_SUB(?, INTERVAL `groups`.`check_minutes` MINUTE)", Time.now) }

I'm not a huge fan of the lambda syntax here, but it does do the job.

Upvotes: 4

Related Questions