ryota21silvaの技術ブログ

Funna(ふんな)の技術ブログ

これまで学んだ技術の備忘録。未来の自分が救われることを信じて

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

qiita.com

qiita.com

qiita.com

qiita.com