JamesWatling
JamesWatling

Reputation: 1185

Rails cause an action to occur after set amount of time

I am working on an application that could be compared to an auction site.

The "auctions" have a set closing date, so my question is how does one set this auction to be "closed" when that time occurs.

For Example

Auction A: Closes 25th December 2012 9:00am.

How do I ensure that it is "closed" at this time?

Upvotes: 2

Views: 794

Answers (2)

doesterr
doesterr

Reputation: 3965

I'd simply go with a timestamp, and methods and scopes for that.

  1. Add a timestamp to your model, maybe call it open_until
  2. define a closed? (and maybe open?) method in your model that checks the timestamp against Time.now
  3. add a closed (and maybe open) scope to your model. Maybe set one of them as the default_scope reference

With this setup you can check on the fly if an Auction is open or closed.

Auction.open.all      #=> all open auctions
Auction.closed.all    #=> all closed auctions
Auction.first.closed? #=> true if 'open_until' is in the past, false otherwise
Auction.first.open?   #=> true if 'open_until' is in the future, false otherwise

If you use a default_scope (e.g. open), and need to find an Auction with another state (e.g. closed) make sure to call Auction.unscoped.closed reference.

When you need the option to close an Auction on the fly (i.e. without waiting for open_until to pass by) you could simply, without additional boolean flags, do this:

def close!
  self.update_attribute(:open_until, 1.second.ago)
end

Upvotes: 3

deefour
deefour

Reputation: 35370

If, for example, you have a :closed attribute on your Auction model you want to set to true at a certain time, you need to have a cron running to periodically run a rake task to check for new Auctions to close.

For example, you can create a file in lib/tasks/close_auctions.rake with something like the following inside

namespace :myapp do
  task "close-auctions" => :environment do
    Auctions.where("closes_at < ? and closed = ?", Time.zone.now, false).update_all(closed: true)
  end
end

This can be called via rake by running

rake myapp:close-auctions

You can then run this rake task on a cron in your crontab. For every minute you'd add something like this to your crontab

* * * * * RAILS_ENV=production rake myapp:close-auctions > /dev/null 2>&1

This means every minute, Rails will find any Auction instances that are still open but which have a :closes_at value that is newly in the past, marking those instances as closed.

Upvotes: 1

Related Questions