Rails メール自動配信機能をActionMailerとwheneverを使用して実装する

Railsで毎日メールを送るためのバッチ処理を、`ActionMailer`とgemの`whenever`を使用して実装しました。

##手順
1. gem `'whenever'`導入
1. `schedule.rb`にバッチ処理を記述
2. `schedule.rb`の内容を登録
1. メールを送信するメソッドを定義
2. viewに送信するメール本文を作成
3. logファイルを確認して実行されているか確認

##環境
ruby '2.5.7'
gem 'rails', '~> 5.2.4', '>= 5.2.4.1'

##前提
1. Userテーブルにemailカラムがあること
1. `ActionMailer`で送信するサーバーの設定が出来ていること
2. メール送信するために必要な`ApplicationMailer`を継承するクラスを作成していること

※ (`UserMailer`という名前で作成済）


## 1. gem `'whenever'`導入

`'whenever'`って？
自動的にメール送信するなど、バッチ処理を行うためにはcronというものを使ってcrontabにそのための記述をします。
でもその小難しいものを簡単に書けるようにするgemが'whenever'です。

それではgem 'whenever'をインストールします。
gemファイルに入力。


```ruby:Gemfile
gem 'whenever', require: false
```
ターミナルでGemをインストールします。

```
$ bundle install
```



## 2. `schedule.rb`にバッチ処理を記述する


まずは`schedule.rb` ファイルを作成します。
以下をターミナルに入力する

```
$ wheneverize .
 [add]  writing './config/schedule.rb'
 [done] wheneverized!
```


今作った`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: '9:00 am' do

# Rails内のメソッド実行
  runner "UserMailer.notify_user"
end

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

```



#### 絶対パスから相対パス指定
`env :PATH, ENV['PATH']`
`ENV['PATH']`を特に何も定義してないけど書いたら上手くいった。
これがないとエラーになるので注意。

#### ログファイルの出力先
`set :output, 'log/cron.log'`
`log/cron.log`が新規作成され、バッチ処理の記録が入る。

####ジョブの実行環境の指定
`set :environment, :development`
`environment`が環境という意味。

`:development `
rails内の開発環境。今回はこれを指定してます。
`:production`
デプロイ後の本番環境
`:test`
テスト実行環境（Rspecなど）

####バッチ処理の記述
`every 1.days, at: '9:00 am' do`
英文そのまま。毎日朝の9時に行います。

`runner "UserMailer.notify_user"`
`UserMailer`内の`notify_user`メソッドを実行します。
※`ApplicationMailer`を継承するクラスの中のメソッドを指定しています。

`runner`
Railsに定義されたメソッドを呼び出すために使用します。
今回の場合は`UserMailer`の`notify_user`メソッドを呼び出すのでこれに当てはまる。
（`UserMailer`は以前に自分で作成したものです）
※ユーザーに直接関係のある機能の場合に使用する。コントローラやモデルを呼び出せる。

`rake`
実行させたいrakeファイルを指定する場合に使用します。
今回は使ってません。使用する場合は別途rakeファイルを作成する。
※システムの管理上必要な機能の場合に使用する。定時になると自動的にデータを削除するなど。


##3. `schedule.rb`の内容を登録する

現状の`crontab`に何が記述されているのかを確認します。


```
$ crontab -e
```

中はいろいろ書いてるけど、先ほど記述した`UserMailer.notify_user`の一文があればOK

※nanoエディタが起動されます。
終了する時は焦らずに`Ctrl + x`


問題がなければ以下のコマンドを実行して登録します。

```
$ bundle exec whenever --update-crontab
```

上記のコマンドで、作成したジョブが`crontab`に登録されました。
反映されているか確認します。

```
$ crontab  -l
```
ちゃんと`UserMailer.notify_user`の記述があれば登録されてます




##4. メールを送信するメソッドを定義

メールを送信する`notify_user`メソッドを定義します。
user全員にメールを送信するようにしてます。

```ruby:mailers/user_mailer
class UserMailer < ApplicationMailer
	def notify_user
		default to: -> { User.pluck(:email) }
		mail(subject: "everyday Bookers!yay!")
	end
end
```

`default to: -> { User.pluck(:email) }`
宛先を指定します。pluckでUserのemailを全て取得する。




```ruby:mailers/application_mailer
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end
```

`application_mailer`には全部のメールに共通する設定を記述します。
`default from: 'from@example.com'`
サーバーに登録してあるメールアドレスが勝手に入ります。



##5. viewに送信するメール本文を作成する

`user_mailer`内に`notify_user.text.erb`と新規作成する。
※textで作成しましたがhtmlでも良い。user.nameなど変数が呼び出せます。


```ruby:user_mailer/notify_user.text.erb

内容を書きます

```


##6. logファイルで実行されているか確認する


実行されているか確認したい場合は、1分毎にメールが送られる設定に書き換えてみましょう。logを確認するためです、仕方ない。
`every 1.days, at: '9:00 am' do`
をコメントアウトして、以下の一文に書き換えます。
`every 1.minutes do`




```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.minutes do ##ここを追加
# every 1.days, at: '9:00 am' do　##ここをコメントアウト

# Rails内のメソッド実行
  runner "UserMailer.notify_user"
end

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

```


忘れずにターミナルで設定を登録します。

```
$ bundle exec whenever --update-crontab
```

logファイルを見ると1分毎にメールが送られているのが確認できます。
下記の通りに1分毎に一行増えて表示されていたらOK
Userにめっちゃメールが送られているのが分かる。

```ruby:log/cron.log
Running via Spring preloader in process 8692
Running via Spring preloader in process 8714
Running via Spring preloader in process 8731
Running via Spring preloader in process 8748

```



##おまけ
そんな頻繁にメールが送られてきたらいやだから`crontab`の中身を消しましょう。
以下のコマンドで消せます。

```
$ whenever --clear-crontab
```

バッチ処理を再開したい時は以下のコマンドを入力。
またメールが送られるようになります。

```
$ bundle exec whenever --update-crontab
```


##参考にさせて頂きました

https://freecamp.life/rails-whenever/
https://qiita.com/Esfahan/items/e7a924f7078faf3294f2
https://www.school.ctc-g.co.jp/columns/masuidrive/masuidrive22.html