wheneverを用いて毎朝9時に記事数一覧メールの送信をする
1. 記事数一覧メールを送信できるように「送信するためのメソッド」と「メール本体」を作成する。
$ rails g mailer ArticleMailer
今回の「送信するためのメソッド」はArticleMailerに記述していく。
(メソッド名はreport_summaryとする)
class ArticleMailer < ApplicationMailer
def report_summary
@publish_article_count = Article.published.count
@article_publish_at_yesterday = Article.published_at_yesterday
mail(to: 'admin@example.com', subject: '公開済記事の集計結果')
end
end
・@publish_article_count
は全ての記事の中で公開されている記事の数を出しているもの
・@article_publish_at_yesterday
は全ての記事の中で公開日が昨日のものを表示している。
・admin@example.com
に送る設定で、題名は「公開済記事の集計結果」
・Article.published_at_yesterday
のpublished_at_yesterday
の部分はscopeを使い指定してやる必要がある(そうじゃないと使えない)
scope :published_at_yesterday, -> { where(published_at: 1.day.ago.all_day) }
@publish_article_count
や@article_publish_at_yesterday
のように各変数を定義することでメール内でその変数、
つまり@publish_article_count=公開記事の総数
と@article_publish_at_yesterday=昨日記事を公開した記事の情報
をメールに表示することができるようになる。
2. メールを書く
次に変数を使ってメールの本文を記述していく(ファイルは$ rails g mailer ArticleMailerをした時に自動生成される)
公開済の記事数: <%= @publish_article_count %>件
<% if @article_publish_at_yesterday.present? %>
昨日公開された記事数: <%= @article_publish_at_yesterday.count %>件
<% @article_publish_at_yesterday.each do |article_yesterday| %>
タイトル: <%= article_yesterday.title %>
<% end %>
<% else %>
昨日公開された記事はありません
<% end %>
このメールでは「公開済の記事数」「昨日公開された記事数」公開されていれば「タイトル」公開されていない場合は「昨日公開された記事はありません」と記述している。
メソッドで定義した変数を使い上記に必要な情報を取得し表示している
3. wheneverを使って毎朝9時に「記事数一覧メールを送信する」というメソッドを実行させていく
1.2でreport_summaryメソッドを実行すればメールが送信されるようになった。
次にwheneverを使い毎朝9時にreport_summaryが実行されるように記述する
every 1.day, at: '9:00 am' do
runner 'ArticleMailer.report_summary'
end
runnerと実行することでrunner以下のメソッドを実行することができるようになる。
ArticleMailerにあるreport_summaryを実行したいので上記のような書き方になる
$ bundle exec whenever --update-crontab
最後に変更をcronに反映させる
メール送信のテストを記述する
メールのテストを記述していく(mailerのspecファイルは$ rails g mailer ArticleMailerの時に自動生成される)
require "rails_helper"
RSpec.describe ArticleMailer, type: :mailer do
let(:article_publish_wait_tomorrow) { create(:article, :article_publish_wait_tomorrow) }
let(:article_published_yesterday) { create(:article, :article_published_yesterday) }
let(:article_published_two_days_ago) { create(:article, :article_published_two_days_ago) }
let(:mail) { ArticleMailer.report_summary.deliver }
let(:check_sent_mail) {
expect(mail.present?).to be_truthy, 'メールが送信されていません'
expect(mail.to).to eq(['admin@example.com']), 'メールの送信先が正しくありません'
expect(mail.subject).to eq('公開済記事の集計結果'), 'メールのタイトルが正しくありません'
}
describe '公開済記事の集計結果通知メールの送信' do
context '昨日までに公開された記事が存在しない場合' do
it '昨日までに公開された記事がない旨の結果が送られること' do
article_publish_wait_tomorrow
check_sent_mail
expect(mail.body).to match('0'), '公開済記事数の件数取得結果が正しくありません'
expect(mail.body).to match('公開済の記事数: 0件'), '公開済記事数の送信フォーマットが正しくありません'
expect(mail.body).to match('昨日公開された記事はありません'), '昨日公開された記事の件数取得結果が正しくありません'
expect(mail.body).not_to match('タイトル: ' + article_publish_wait_tomorrow.title), '公開されていない記事のタイトルを取得しています'
end
end
context '公開日が昨日の記事が存在する場合' do
it '公開日が昨日の記事を含めた集計結果が送られること' do
article_publish_wait_tomorrow
article_published_yesterday
check_sent_mail
expect(mail.body).to match('1'), '公開済記事数の件数取得結果が正しくありません'
expect(mail.body).to match('公開済の記事数: 1件'), '公開済記事数の送信フォーマットが正しくありません'
expect(mail.body).to match('昨日公開された記事数: 1件'), '昨日公開された記事の件数取得結果が正しくありません'
expect(mail.body).not_to match('タイトル: ' + article_publish_wait_tomorrow.title), '公開されていない記事のタイトルを取得しています'
expect(mail.body).to match(article_published_yesterday.title), '昨日公開された記事のタイトルが取得されていません'
expect(mail.body).to match('タイトル: ' + article_published_yesterday.title), '昨日公開された記事のタイトルの送信フォーマットが正しくありません'
end
end
context '公開日が2日前の記事が存在する場合' do
it '公開日が2日前の記事を含めた集計結果が送られること' do
article_publish_wait_tomorrow
article_published_two_days_ago
check_sent_mail
expect(mail.body).to match('1'), '公開済記事数の件数取得結果が正しくありません'
expect(mail.body).to match('公開済の記事数: 1件'), '公開済記事数の送信フォーマットが正しくありません'
expect(mail.body).to match('昨日公開された記事はありません'), '昨日公開された記事の件数取得結果が正しくありません'
expect(mail.body).not_to match('タイトル: ' + article_publish_wait_tomorrow.title), '公開されていない記事のタイトルを取得しています'
expect(mail.body).not_to match('タイトル: ' + article_published_two_days_ago.title), '昨日以前に公開された記事のタイトルを取得しています'
end
end
context '公開日が昨日と2日前の記事が存在する場合' do
it '公開日が昨日と2日前の記事を含めた集計結果が送られること' do
article_publish_wait_tomorrow
article_published_yesterday
article_published_two_days_ago
check_sent_mail
expect(mail.body).to match('2'), '公開済記事数の件数取得結果が正しくありません'
expect(mail.body).to match('公開済の記事数: 2件'), '公開済記事数の送信フォーマットが正しくありません'
expect(mail.body).to match('昨日公開された記事数: 1件'), '昨日公開された記事の件数取得結果が正しくありません'
expect(mail.body).not_to match('タイトル: ' + article_publish_wait_tomorrow.title), '公開されていない記事のタイトルを取得しています'
expect(mail.body).to match(article_published_yesterday.title), '昨日公開された記事のタイトルが取得されていません'
expect(mail.body).to match('タイトル: ' + article_published_yesterday.title), '昨日公開された記事のタイトルの送信フォーマットが正しくありません'
expect(mail.body).not_to match('タイトル: ' + article_published_two_days_ago.title), '昨日以前に公開された記事のタイトルを取得しています'
end
end
end
end
#上記省略
trait :article_publish_wait_tomorrow do
state { :publish_wait }
published_at { Time.current.tomorrow }
category
end
trait :article_published_yesterday do
state { :published }
published_at { Time.current.yesterday }
category
end
trait :article_published_two_days_ago do
state { :published }
published_at { Time.current.ago(2.days) }
category
end
end
1. letの記述
require "rails_helper"
RSpec.describe ArticleMailer, type: :mailer do
let(:article_publish_wait_tomorrow) { create(:article, :article_publish_wait_tomorrow) }
let(:article_published_yesterday) { create(:article, :article_published_yesterday) }
let(:article_published_two_days_ago) { create(:article, :article_published_two_days_ago) }
let(:mail) { ArticleMailer.report_summary.deliver }
let(:check_sent_mail) {
expect(mail.present?).to be_truthy, 'メールが送信されていません'
expect(mail.to).to eq(['admin@example.com']), 'メールの送信先が正しくありません'
expect(mail.subject).to eq('公開済記事の集計結果'), 'メールのタイトルが正しくありません'
}
・article_publish_wait_tomorrow
article_published_yesterday
article_published_two_days_ago
はarticleにそれぞれ独自の公開日時を指定したものになる。これで公開日時によって動作が変わるテストを行うことができるようになる
・let(:mail)は ArticleMailer.report_summary.deliver
でArticleMailerクラスのreport_summaryメソッドを実行する、つまりメールを送信するということ
・ expect(mail.present?).to be_truthy
expect(mail.to).to eq(['admin@example.com'])
expect(mail.subject).to eq('公開済記事の集計結果')
は何度も使うのでまとめて使えるようにしておく
・メールのテストではexpect(mail.実行結果)
を記述する。
・expect(mail.present?).to be_truthy
ではmail.present?がtrueならtrueを返す。逆にexpect(mail.present?).to be_falsey
はmail.present?がfalseならtrueを返す
2. テスト記述
describe '公開済記事の集計結果通知メールの送信' do
context '昨日までに公開された記事が存在しない場合' do
it '昨日までに公開された記事がない旨の結果が送られること' do
article_publish_wait_tomorrow
check_sent_mail
expect(mail.body).to match('0'), '公開済記事数の件数取得結果が正しくありません'
expect(mail.body).to match('公開済の記事数: 0件'), '公開済記事数の送信フォーマットが正しくありません'
expect(mail.body).to match('昨日公開された記事はありません'), '昨日公開された記事の件数取得結果が正しくありません'
expect(mail.body).not_to match('タイトル: ' + article_publish_wait_tomorrow.title), '公開されていない記事のタイトルを取得しています'
end
end
・expect(mail.body).to match
を使ってそれぞれ想定している単語がマッチしているかの確認をする。