目的
- 自分用のメモです
- 条件
- WordPressみたいなブログサイト
- 記事のステータスは、「下書き」「公開待ち」「公開」の3種類
- 記事を保存時に上記ステータスと公開日(日付)の設定が必須
- 「公開待ち」の記事で期限到来日(公開日)によりステータスを自動で「公開」に変更
動作環境
- ruby 2.5.0
- Rails 5.2.0
- mysql Ver 14.14 Distrib 5.7.22
手順リスト
- 「rails g task」コマンドでタスク(処理)を作成
- gem 'whenever'を導入し、タスクを定期的にバッチ処理
1. 「rails g task」コマンドでタスク(処理)を作成
タスクファイルを生成
rails g task check_date
# lib/tasks/check_date.rakeにファイルが生成される
app/models/article.rb
# enumの設定です [下書き 公開待ち 公開]
enum state: %i[draft wait_publish published]
lib/tasks/check_date.rake
namespace :check_date do
desc "check_state" # このタスクの説明を書く
# タスクの名前。 「:environment」がないとDBやモデルにアクセスできないので、使う場合は付ける
task check_state: :environment do
Article.where('published_at <= ?', Time.zone.now).wait_publish.each(&:published!)
# articlesテーブルで[公開日が現在時刻以前かつステータス「公開待ち」]のものを全て「公開」に変更
end
end
処理が本当に走るのか確認する
タスクの一覧を表示
rails -T
ここで、タスク処理の設定は完了です。
次は、設定したタスクを定期的にバッチ処理を行うよう設定していきます。
2. gem 'whenever'を導入し、タスクを定期的にバッチ処理
Gemfile
# crontab管理
gem 'whenever', require: false
# 上記を記載後、bundle install
設定ファイルを作成
bundle exec wheneverize .
> [add] writing './config/schedule.rb' #<= 設定ファイルが生成
> [done] wheneverized! #<= 成功
config/schedule.rb
# Rails.rootを使用するために必要。なぜなら、wheneverは読み込まれるときにrailsを起動する必要がある
require File.expand_path(File.dirname(__FILE__) + "/environment")
# cronを実行する環境変数
rails_env = ENV['RAILS_ENV'] || :development
# cronを実行する環境変数をセット
set :environment, rails_env
# cronのログの吐き出し場所。ここでエラー内容を確認する
set :output, "#{Rails.root}/log/cron.log"
# 3時間ごとに[lib/tasks/check_date.rake]を実行する
every 3.hours do
rake 'check_date:check_state'
end
# [課題]
# メモ:厳密に言うとこのコードにはバグが含まれていると思っていて、3時間おきにタスク実行させているので!
# 例えば12:00にタスクが走った後、公開時刻が12:01の記事があった場合でも、次にタスクが走るのは15:00、つまり15:00にならないと公開状態にならないようなコードとなっています。
# 既存のものに修正を加えるとなると、色々とデータの整合性を保たなければいけなくなるので、
# その辺今後意識していきましょう。
# [試したこと]
# コールバックを設定したけど、それだとSQLを走らせる回数が増えるのでよくない。
Corntabへの設定
# 設定内容にエラーがないか確認
bundle exec whenever
# 設定されているcronを見る
crontab -l
# wheneverの設定更新
RAILS_ENV=development bundle exec whenever --update-crontab
# crontabの設定削除
RAILS_ENV=development bundle exec whenever --clear-crontab
気づき
config/application.rb
config.autoload_paths += %W(#{config.root}/lib)
あまり考えずに設定してたけど、Rails5のproduction環境では不具合がでるので注意しとく。
Rails5のproduction環境でlib/配下のクラス読込みがNameErrorになるのはautoloadが無効化されたからだった
Rails5: production環境でのAutoloadの廃止
参考