【Rails】バッチ処理(whenever)で、1日1回メールを自動配信してみる

ActionMailerとバッチ処理（whenever）を使って、指定頻度でメールを自動送信する方法をまとめています。

# 大まかな流れ #
1. メール送信用サーバーの設定（他の記事に飛びます）
1. DailyMailerを生成
1. ApplicationMailerとDailyMailerを編集
1. メール本文の作成
1. ```whenever```を導入
1. ```schedule.rb```を生成して、バッチ処理を記述
1. cronにバッチ処理を反映する
1. 処理が実行できているかlogファイルから確認

### 前提 ###
 
- Userモデルを作成した、かつusersテーブルにはemailカラムがあることを前提としています
- STEP1の「メール送信用サーバの設定」ではGmailを使用するので、Googleアカウントを一つ用意してください。練習用の場合は、サブのアカウントや練習用アカウントで試される方が安心かと思います
- この記事は、[以前私が書いた記事](https://qiita.com/mi-1109/items/974c03776eba61146aa4)と「手順4」まで重複部分があるため、部分的に抜粋・流用しています。ご了承ください。
- すでにMailerを生成・編集し、メール本文の作成も終わっている場合は、「手順5」に進んでください。


# 実装手順 #
ではさくさくいきましょう！

## 手順1. メール送信用サーバーの設定 ##
こちらについては、[わたしが以前書いた記事](https://qiita.com/mi-1109/items/974c03776eba61146aa4)の「STEP1～STEP2」に記載しているので、割愛します。
STEP2まで終わったら、この記事の「手順2」に進んでください。

## 手順2. DailyMailerを生成 ##

ターミナルで以下のコマンドを実行し、```DailyMailer```と```daily_notification```メソッドを一緒に生成します。Mailer名とメソッド名は好きなものを指定してOKです。

今回は1日1回の自動配信を例にとっていくので、Mailer名もメソッド名もそうしています。

```ruby:terminal
$ rails g mailer DailyMailer daily_notification
# rails g mailer  <Mailer名>    <メソッド名>
```
これにより、以下が生成されます：

- ```app/mailers```配下に、```application_mailer.rb```と```daily_mailer.rb```
- ```app/views/daily_mailer```配下に、viewファイル（ ```html.erb```ファイルと```text.erb```）

※メソッドは、Mailerと一緒に生成しなくても大丈夫ですが、手順4でメール本文を作成する際に自分でviewファイルを作成する工程が発生するので、この段階でメソッドごと生成してしまう方が手間がないかと思います。

## 手順3. ApplicationMailerとDailyMailerの編集 ##

まず、```application_mailer.rb```には、すべてのMailerに共通の設定を記述します。これに対し、```daily_mailer.rb```には、DailyMailerに固有の設定を記述します。

なお、```application_mailer.rb```はデフォルトの記述のままでも動作するので、単に練習用・勉強用ということであれば、```daily_mailer.rb```の編集に進んでもOKです

**```application_mailer.rb```を編集**

```Ruby:app/mailers/application_mailer.rb
#デフォルトの記述
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end

#編集例
class ApplicationMailer < ActionMailer::Base
  default from:     "〇〇事務局",
          cc:       "hogehoge@gmail.com"
          bcc:      "hoge_hoge@gmail.com"
  layout 'mailer'
end
```

👆の```defalut```メソッドは、共通の設定を記述する際に使用するもので、以下のような項目についてデフォルト値の指定が可能です：

|  項目  |  内容  |
| ---- | ---- |
|  to  |  メインの送信先  |
|  cc  |  メインではないが、共有しておきたい送信先  |
|  bcc |  他の人に見られずに共有しておきたい送信先  |
|  subject |  メールのタイトル  |
|  from |  メールの送信元の名前  |
|  reply_to |  返信先のメールアドレス  ​
|  date |  メールの送信日時  ​|


**```daily_mailer.rb```を編集**
こちらには、メール送信時に呼ばれる```daily_notification```メソッドを定義します。

```Ruby:app/mailers/daily_mailer.rb

def daily_notification
    default to: -> { User.pluck(:email) }
    mail(subject: "Daily Report of Your Record")
end
```

詳しく見ていきましょう：

- ```default to```で宛先を指定。宛先は、登録しているユーザー全員に自動配信する場合、```User.pluck(:email)```とし、Userのemailすべてを取得できる
-   ```subject```には任意の件名を指定できる


## 手順4. メール本文の作成 ##

メールの内容は好きな内容で記入してください。

HTMLファイルで受け取れない/受け取りたくないuserがいる可能性もあるので、テキストファイルもあわせて用意しておくのが推奨されているようです。

```:app/views/daily_mailer/daily_notification.html.erb

<h2>Today's Record</h2>

<p>Here is the update on your record today!</p>
<p>Don't forget to check on our website</p>

<p>Sincerely,</p>
<p>Team ABC</p>
```

```:app/views/daily_mailer/daily_notification.text.erb
-------------------------------
       Today's Record
-------------------------------

Here is the update on your record today!
Don't forget to check on our website

Sincerely,
Team ABC
```


## 手順5. ```whenever```を導入 ##

さて、いよいよ```whenever```を入れていきます。
ちなみに```whenever```は、バッチ処理を行うためにcronを後で使用しますが、その設定を簡単に書けるgemのことです。

```Ruby:Gemfile

# ---- 前略 ---- #
gem 'whenever', require: false
end
```

```:terminal
$ bundle install
```


## 手順6. ```schedule.rb```を生成して、バッチ処理を記述 ##

次に、 ```schedule.rb```ファイルにバッチ処理の内容を記述していきます。
👇 まず ```schedule.rb```をコマンドで生成しましょう

```:terminal
$ wheneverize .
```

👇 ```schedule.rb```を開いて、バッチ処理を記述していきます

```Ruby:config/schedule.rb
# Use this file to easily define all of your cron jobs.
#
# It's helpful, but not entirely necessary to understand cron before proceeding.
# http://en.wikipedia.org/wiki/Cron

# Example:
#
env :PATH, ENV['PATH']
set :output, "log/cron.log"  #ログファイルの出力先を指定
set :environment, :development
#
# every 12.hours do
#   command "/usr/bin/some_great_command"
#   runner "MyModel.some_method"
#   rake "some:great:rake:task"
# end
#

every 1.days, at: '6:00 pm' do

# DailyMailerのdaily_notificationメソッド実行
  runner "DailyMailer.daily_notification"
end

# Learn more: http://github.com/javan/whenever
```

👆では、```every 1.days, at: '6:00 pm'```によって、毎日6：00PMにメールが自動配信されるように設定されています。

もし何時間おき、何分おき、といったように設定したい場合は、```every 12.hours do```や```every 10.minutes do```のように記述すればOKです。


## 手順7. cronにバッチ処理を反映する ##

さて、```whenever```では、```schedule.rb```に記述した内容（バッチ処理）がcrontabに反映される仕組みになっているので、早速反映させていきましょう。

```Ruby:terminal
$ bundle exec whenever --update-crontab
  [write] crontab file updated  #このように表示されていれば成功
```
次に、crontabに反映されているか確認します

```Ruby:terminal
$ crontab -l
#DailyMailer.daily_notificationの記述があればOK
```

## 手順8. 処理が実行できているかlogファイルから確認 ##

さて、```schedule.rb```に先ほど```set :output, "log/cron.log"```を記述したのを覚えているでしょうか。

もし処理が正常に動いていて、メールが指定間隔・時間に自動配信できていれば、このlogファイルが生成されて、以下のような記述が、処理ごとに1行ずつ記述されているはずです。

```Ruby:log/cron.log
Running via Spring preloader in process xxxx
Running via Spring preloader in process yyyy
```

👇 最後に。
もし勉強用・練習用に作成した場合は、cronからデータを削除してバッチ処理を停止しておきましょう！

```Ruby:terminal
$ bundle exec whenever --clear-crontab
```

#参考資料

-[Rails メール自動配信機能をActionMailerとwheneverを使用して実装する](https://qiita.com/sato028/items/222ba63e3b333c80bb79#4-%E3%83%A1%E3%83%BC%E3%83%AB%E3%82%92%E9%80%81%E4%BF%A1%E3%81%99%E3%82%8B%E3%83%A1%E3%82%BD%E3%83%83%E3%83%89%E3%82%92%E5%AE%9A%E7%BE%A9)
-[Railsでwheneverを使ってcronを設定する](https://qiita.com/Esfahan/items/e7a924f7078faf3294f2)
-[Railsでメール自動配信機能をつくるまでの道程](https://qiita.com/Yama-to/items/823baf26bba3193712ea)