7

I need to erase records in my offers models if the record has more that 60 days from the created_at date.

I only found information about how to populate my model with a rake task, but I couldn't find information about how to make a rake task to delete records. So I just wonder if I have to do this with a task or if rails has something else to do this.

John H
  • 2,488
  • 1
  • 21
  • 35
Jean
  • 5,201
  • 11
  • 51
  • 87

4 Answers4

20

Create a file for the task:

# lib/tasks/delete_old_records.rake
namespace :delete do
  desc 'Delete records older than 60 days'
  task :old_records => :environment do
    Model.where('created_at < ?', 60.days.ago).each do |model|
      model.destroy
    end

    # or Model.delete_all('created_at < ?', 60.days.ago) if you don't need callbacks
  end
end

Run with:

RAILS_ENV=production rake delete:old_records

Schedule it to run with cron (every day at 8am in this example):

0 8 * * * /bin/bash -l -c 'cd /my/project/releases/current && RAILS_ENV=production rake delete:old_records 2>&1'

You can also use the whenever gem to create and manage your crontab on deploys:

every 1.day, :at => '8:00 am' do
  rake "delete:old_records"
end

Learn more about the gem on Github.

Eduardo
  • 508
  • 6
  • 18
Unixmonkey
  • 18,485
  • 7
  • 55
  • 78
  • Thanks, I'll going to accept your answer and use the whenever gem as dimuch said on his answer. But I have to wait 4 more minutes to accept yours. – Jean Dec 20 '12 at 15:38
  • 1
    `...each(&:destroy)` looks prettier :) – jdoe Dec 20 '12 at 15:39
  • 1
    @jdoe It may look prettier, but it's inefficient to put a DB operation in a loop. `where().destroy`, OTOH, *should* generate only one DB query (although I haven't tested to make sure!) and therefore is the proper way of doing this. General rule: DB queries don't belong inside loops; instead, use the power of the DB to make one big query. – Marnen Laibow-Koser Dec 20 '12 at 15:45
  • 1
    @MarnenLaibow-Koser I don't think `where().destroy` works. `Model.delete_all('created_at > ?', 60.days.ago)` would be the way to do it all in one query, but that skips callbacks. `destroy_all`, doesn't, but then you are loading one record at a time again. – Unixmonkey Dec 20 '12 at 15:53
  • @Unixmonkey I'd normally use `delete_all` myself, but I didn't specifically recommend it precisely because it skips callbacks (which I've mostly stopped using). But you're right that `where().destroy` doesn't work. The ARel way to do use `delete_all` seems to be `Model.where().delete_all`. I can't find any ARel syntax for `destroy_all`, but `destroy_all(conditions: 'hash')` appears to work. So my advice would now be to use `where().delete_all` if you don't need the callbacks, or `destroy_all` if you do (efficiency is perhaps less important in a cron job). – Marnen Laibow-Koser Dec 20 '12 at 21:47
  • It might also possible to use the DB to expire records without invoking the application. I don't know if this is a good idea, though. – Marnen Laibow-Koser Dec 20 '12 at 21:47
  • 2
    60.days.ago produces a time stamp Fri, 08 Aug 2014 15:57:18 UTC +00:00. So you'd need to use < in your query instead of > if you want to find older records. – Natus Drew Oct 07 '14 at 15:58
12

60.days.ago generates a timestamp like

Fri, 08 Aug 2014 15:57:18 UTC +00:00

So you'd need to use < to look for records older(less) than the timestamp.

Online.delete_all("created_at < '#{60.days.ago}'")

It's just a slight oversight by Unixmonkey. I'd also use the delete_all instead of looping each iterating in a block.

Natus Drew
  • 1,876
  • 1
  • 21
  • 23
4

You can create a rake task to delete expired offers , or create class method for your offers model and call it using, for example, whenever gem.

Community
  • 1
  • 1
dimuch
  • 12,728
  • 2
  • 39
  • 23
0

You can delete all records older than 60 days in a single query like so:

Model.where("created_at < '#{60.days.ago}'").delete_all
Chris Harrison
  • 5,512
  • 3
  • 28
  • 36