Rails

Rakeタスクをつくる

More than 5 years have passed since last update.

定期的なメンテナンスをRakeタスクとして登録して呼び出したいと考えました。
Rakeタスクの作り方を調べたのでメモ。

シナリオは、メール認証が一週間以上されないユーザーのレコードを削除するです。

$ rails g task inactive_user #=> inactive_userが名前

#=> rake inactive_user:xxx のように使うので名前に気をつけて
lib/tasks/destroy_inactive_user.rake
# encoding: utf-8

namespace :inactive_user do
    desc "Users中confirm_atから1週間が経過していれば削除" #=> 説明

# $ rake inactive_user:destroy_unconfirmed のように使う
# :environmentは超大事。ないとモデルにアクセスできない

    task :destroy_unconfirmed => :environment do 
        User.all.each do |user|
            user.destroy if (Time.now > user.confirm_at + 1.weeks.ago)
        end
    end
end

これでOK
タスクが登録されているか確認してみる

$ rake -vT

# 略
rake inactive_user:destroy_suspended    # Users中suspended_atから3ヶ月経過していていれば削除
rake inactive_user:destroy_unconfirmed  # Users中confirm_atから1週間が経過していれば削除
rake inactive_user:list_suspended       # Users中suspended_atから3ヶ月経過していていれば表示
rake inactive_user:list_unconfirmed     # Users中confirm_atから1週間が経過していれば表示

ちゃんと入ってますね。

実際に動かしてみる、、、前にいきなり削除すると怖いので、

lib/tasks/destroy_inactive_user.rake
# encoding: utf-8

namespace :inactive_user do
    desc "Users中confirm_atから1週間が経過していれば削除"
    task :destroy_unconfirmed => :environment do 
        User.all.each do |user|
            puts user.to_yaml if (Time.now > user.confirm_at + 1.weeks.ago)
        end
    end
end

こう変えましょう。
先にデータベースの下ごしらえをします。
モデルは何となく想像してください。

$ rails c

>> User.create({:name => "new", :email =>"a@example.com", :confirmed => false, :confirm_at => Time.now}) #=> 成功すること

>> User.create({:name => "old", :email =>"b@example.com", :confirmed => false, :confirm_at => 1.weeks.ago})  #=> 成功すること

実行します。

$ rake inactive_user:destroy_unconfirmed

--- !ruby/object:User
attributes:
  id: 3
  name: old
  email: b@example.com
  created_at: 2012-09-18 10:42:32.000000000 Z
  updated_at: 2012-09-18 10:42:32.000000000 Z
  confirmed: false
  confirm_at: 2012-09-11 10:42:32.000000000 Z

ちゃんと捕捉できました。
では削除用スクリプトに書き直して、、、ログも残しておきたいですよね?

lib/tasks/destroy_inactive_user.rake
# encoding: utf-8

namespace :inactive_user do
    desc "Users中confirm_atから1週間が経過していれば削除"
    task :destroy_unconfirmed => :environment do 
        User.all.each do |user|
            logger = Logger.new('log/inactive_user.log')
            logger.info "#{Time.now} -- destroy_unconfirmed_inactive_user -- #{user.to_yaml}"
            user.destroy if (Time.now > user.confirm_at + 1.weeks.ago)
        end
    end
end

こうしました。
実行します。

$ rake inactive_user:destroy_unconfirmed

Process finished with exit code 0
log/inactive_user.log
# Logfile created on 2012-09-18 19:58:37 +0900 by logger.rb/31641

2012-09-18 19:58:37 +0900 -- destroy_unconfirmed_inactive_user -- --- !ruby/object:User
attributes:
  id: 3
  name: old
  email: b@example.com
  created_at: 2012-09-18 10:42:32.000000000 Z
  updated_at: 2012-09-18 10:42:32.000000000 Z
  confirmed: false
  confirm_at: 2012-09-11 10:42:32.000000000 Z

ログもとれました。
以上で機能を達成できましたが、もっと良い方法だったり問題点があれば教えてください。
具体的なシナリオを言及した投稿がもっとたくさんあるといいですね。