Rakeタスクのメモ的な(メールの自動配信機能)
Rakeタスク
タスクファイル作成
rails g task mail_summary
タスクファイルの編集
(lib/tasks/mail_summary.rake) namespace :mail_summary do desc '公開済の記事の件数と、昨日公開された記事の件数とタイトルをメールで送信' # task :article doだとDBには接続しない task article: :environment do # mailerのメソッドを呼び出す # articles = Article.all ArticleMailer.report_summary.deliver_now end end
メールをcronjobなどから今すぐ送信したい場合は、deliver_now でいつでも実行できる。
# すぐにメール送信したい場合は#deliver_nowを使用 UserMailer.welcome(@user).deliver_now # Active Jobを使用して後でメール送信したい場合は#deliver_laterを使用 UserMailer.welcome(@user).deliver_later
一般に、非同期キュー(.deliver_laterでメールを送信するなど)はRakeタスクに書いても動きません。Rakeが終了すると、.deliver_laterがメールの処理を完了する前にインプロセスのスレッドプールを削除する可能性があるためです。この問題を回避するには、.deliver_nowを用いるか、development環境で永続的キューを実行してください。
これをdeliver_later
にすると、メールが届かなかった。
ArticleMailer.report_summary.deliver_later
講師 deliverは非推奨、deliver_nowは同期処理、deliver_laterは非同期処理 nowだと同期処理だからキューに入らないと思う もしSidekiqとかResqueのような永続化キューを使用してない場合、rakeタスクの中でdeliver_laterするとメール届かない可能性があるみたい。deliver_laterでメールの送信処理を完了する前にrakeタスクのプロセスが終わる可能性があるかららしい。
タスク一覧
rake -vT rake mail_summary:article # 公開済の記事の総記事数と、昨日公開された記事の件数とタイトルをメールで送信 rake status_update:article_status # 記事が公開待ち状態で、公開日時が過去の場合、ステータスを「公開」にする
タスク実行
rake status_update:article_status
Mailer
$ rails g mailer ArticleMailer report_summary Running via Spring preloader in process 99411 create app/mailers/application_mailer.rb create app/mailers/article_mailer.rb invoke erb create app/views/layouts/mailer.html.erb create app/views/layouts/mailer.text.erb create app/views/article_mailer create app/views/article_mailer/report_summary.html.erb create app/views/article_mailer/report_summary.text.erb
(app/mailers/application_mailer.rb) class ApplicationMailer < ActionMailer::Base default from: 'from@example.com' layout 'mailer' end
- 良い書き方
(app/mailers/article_mailer.rb) class ArticleMailer < ApplicationMailer # 共通処理を書く。 # article_mailer/report_summary.~のビューを呼び出す def report_summary(articles) @published_articles = articles.published @published_articles_yesterday = Article.published_yesterday mail(to: 'admin@example.org', subject: '公開記事の集計結果') end end
- 良くない書き方
# BAD: # @published_articles_yesterday = @published_articles.where('? <= published_at && published_at <= ?', Time.current.yesterday.beginning_of_day, Time.current.yesterday.end_of_day) # SOSO: # @published_articles_yesterday = @published_articles.where(published_at: Time.current.yesterday.all_day)
- scopeを定義
(app/models/article.rb) scope :published_yesterday, -> { where(published_at: 1.day.ago.all_day) }
# メーラーメソッドでcountしておくのもあり @published_articles_count = articles.published
(app/views/layouts/mailer.html.erb) <html> <body> <%= yield %> </body> </html>
(app/views/article_mailer/report_summary.html.erb) <p>公開済の記事数: <%= "#{@published_articles.count}" %>件</p> <% if @published_articles_yesterday.present? %> <p>昨日公開された記事数: <%= "#{@published_articles_yesterday.count}" %>件</p> <% @published_articles_yesterday.each do |article| %> <p>タイトル: <%= article.title %></p> <% end %> <% else %> <p>昨日公開された記事はありません</p> <% end %>
Letter Opener
https://github.com/ryanb/letter_opener ・実際にメールを送信するのではなく、デフォルトのブラウザでメールをプレビューする。 これにより、開発環境で実際にメールを送らずに済む。
(config/environments/development.rb) # letter_opener_webの設定 config.action_mailer.delivery_method = :letter_opener_web config.action_mailer.default_url_options = 'localhost:3000'
(app/views/password_resets/edit.html.erb) <%= form_with model: @user, url: password_reset_path(@token), local: true do |f| %> 引数の@token無しでもいけた。。。 <%=form_withmodel:@user, url:password_reset_path, local:truedo |f| %>
Whenever
config/schedule.rb # 初期設定ファイル # このファイルを使って、すべてのcronジョブを簡単に定義することができます。 # Rails.rootを使用するために必要(cronはRailsとは全く別物だから) require File.expand_path(File.dirname(__FILE__) + '/environment') # cronを実行した際のログを出力するファイルを指定 set :output, "#{Rails.root}/log/cron.log" # TODO: cronログの出力内容を記述できてないっぽい # cronを実行する環境 set :environment, :development every :minute do rake 'status_update:article_status' end every 1.day, at: '9:00 am' do rake 'mail_summary:article' end
config/schedule.rbをcron構文に変換した内容を表示してくれてるが、crontabファイルが更新されているわけではない。
$ be whenever * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake status_update:article_status --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake mail_summary:article --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' ## [message] Above is your schedule file converted to cron syntax; your crontab file was not updated. ## [message] Run `whenever --help' for more options.
設定されているcronを確認
$ crontab -l # Begin Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-14 16:09:28 +0900 0 * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake status_update:article_status --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' # End Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-14 16:09:28 +0900
cronにデータを反映させる
$ bundle exec whenever --update-crontab [write] crontab file updated
OKを押す。
再度cronを確認するとデータが反映されていることがわかる
$ crontab -l # Begin Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-31 22:22:28 +0900 * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake status_update:article_status --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' * * * * * /bin/bash -l -c 'cd /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced && RAILS_ENV=development bundle exec rake mail_summary:article --silent >> /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/log/cron.log 2>&1' # End Whenever generated tasks for: /Users/funesakisuke/workspace/runteq/332_ryota1116_runteq_learning_advanced/config/schedule.rb at: 2020-05-31 22:22:28 +0900
cronからデータを削除する
$ bundle exec whenever --clear-crontab