【Rails】wheneverでバッチ処理を行う(未読通知が3件以上溜まったらAction Mailerでメール送信）

wheneverで定期的にバッチ処理を行い、「未読通知が3件以上溜まったらAction Mailrでメール送信」する実装方法を記載します。対象者には毎朝午前８時に下記のようなメールが送信されます。

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642283/f4ae0b49-d36f-7192-1128-f76bd30cc2f5.jpeg" width=30%>

# 前提
* 通知機能を実装ずみ


![スクリーンショット 2020-08-26 14.01.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642283/2a92cdd3-76cb-fe6e-50cf-56ce3719b126.png)

私の場合は上記のような通知機能を作成済みです。


# 大まかな流れ
1. Action Mailerでメーラー生成
2. 「未読３件以上のユーザーを見つけてメールを送る」処理をアクションメーラで定義
3. メール文面作成
4. wheneverの導入
5. 2を１日に１回、wheneverで実行(メール送信）

# 実装方法

## 1. Action Mailerでメーラー生成
* Action Mailerの基本については下記の記事に詳しく載っています

[【Rails入門説明書】Action Mailerについて解説](https://web-camp.io/magazine/archives/19143)
[【初心者向け】Ruby on Railsアプリでメール送信機能を実装する方法](https://freesworder.net/rails-mail/)

* メーラーを生成

```
rails g mailer ScheduledProcessing
```
下記のファイルができる

|フォルダ・ファイル名                   　　　　           |                           |
|:---------------------------------------           |:------------------------- |
| app/meilers/application_mailer.rb          　　　  |controllerみたいなイメージ　　　|
| app/meilers/scheduled_processing_mailer.rb 　　　　|controllerみたいなイメージ     |
| app/views/scheduled_processing_mailer (フォルダ）    | viewみたいなイメージ          |

## 2. 「未読３件以上のユーザーを見つけてメールを送る」処理をアクションメーラで定義

* app/meilers/application_mailer.rb

```
class ApplicationMailer < ActionMailer::Base
  default from: "ノミジョイ！チーム(ここは送り先。任意の名前を入力） <delivery@nomijoy.com>"
  layout 'mailer'
end
```

* app/meilers/scheduled_processing_mailer

```
class ScheduledProcessingMailer < ApplicationMailer
  def check_notice_mail
    @url = "https://nomi-joy.com/users/sign_in"

    users_with_unckecked_notices = User.all.select do |user|
      user.passive_notifications.where(visited_id: user.id, checked: false).count >= 3
    end

    users_with_unckecked_notices_mails = users_with_unckecked_notices.pluck(:email)

    mail(subject: "未読の通知が3件以上あります", bcc: users_with_unckecked_notices_mails)
  end
end
```
メソッド名を`check_notice_mail`にしていますが、ここは任意で問題ありません。
`@url = "https://nomi-joy.com/users/sign_in"`は、送信するメールにアプリケーションのログイン画面へとぶURLを表示したかったので記載しましたが必要なければ記載しなくてOKです。

selectは返り値が真の要素を集めた配列を返すメソッドなので、`users_with_unckecked_notices`は未読通知が3件以上のUserたちの配列になっています。
**「今いる全Userを一人ずつ調べる。userに紐づく（受信）通知が未読通知が3件以上あるかどうかを。それが真なら該当するUserを配列にする。配列にしたものがusers_with_unckecked_notices。」**という感じです。


'user.passive_notifications.where(visited_id: user.id, checked: false)'は通知機能の設計によって変わるかと思いますので適宜ご自身の実装に合わせて変更してください。

pluckは引数に設定したカラム（ここではemail)のデータのみ集めて配列にしてくれるメソッドです。なので、`users_with_unckecked_notices_mails`は下記のようになっています。

```
users_with_unckecked_notices_mails
=> ["test1@test.co.jp","test2@test.co.jp"]
```
'mail(subject: "未読の通知が3件以上あります", bcc: users_with_unckecked_notices_mails)'でメールを送信します。bccをtoに置き換えてもOKです。


# 3. メール文面作成
* app/views/scheduled_processing_mailer (フォルダ）  に下記ファイルを新規作成
* 
|ファイル名                   　　　　           |                           |
|:---------------------------------------           |:------------------------- |
| check_notice_mail.html.erb                 　　　  |html                  　　　|
| check_notice_mail.text.erb                 　　　　|text                       |

* check_notice_mail.html.erb  
* 
```
<!doctype html>
<html lang="ja">
<head>
  <meta content="text/html; charset=UTF-8" />
  <style>
  /* h2,p{
  color:#215c89;
  } */
  </style>
</head>
<body> 
    <hr>
    <h3>未読の通知が3件以上あります</h3>
    <hr>
    <p>通知は【フォローされたとき】、【ダイレクトメッセージが届いたとき】、【新規ノミカイに招待されたとき】、【カンジから何かしらの連絡を受けたとき】に届きます。</p>
    <p>◆詳細は下記よりログインして【Notice（通知）】からご確認いただけます。</p>
    <p>&ensp;ノミジョイ！ログインページ：<br>&ensp;<%= @url %></p>
    <br>
    <p>※このメールは送信専用です。</p>
    <hr>
    <h3>ノミジョイ！チーム</h3>
    <hr>
  </body>
</html>
```
* check_notice_mail.text.erb

```
===============================
 未読の通知が3件以上あります
===============================
通知は【フォローされたとき】、【ダイレクトメッセージが届いたとき】、【新規ノミカイに招待されたとき】、【カンジから何かしらの連絡を受けたとき】に届きます。

◆詳細は下記よりログインして【Notice（通知）】からご確認いただけます。
  ノミジョイ！ログインページ：
  <%= @url %>

※このメールは送信専用です。
===============================
 ノミジョイ！チーム
===============================
```

# 4. wheneverの導入
* こちらの記事を参考に設定する

[Rails メール自動配信機能をActionMailerとwheneverを使用して実装する](https://qiita.com/sato028/items/222ba63e3b333c80bb79)

# 5. 2を１日に１回、wheneverで実行(メール送信）
* schedule.rbを下記に変更（下記は開発環境を前提の記述）

```
# 絶対パスから相対パス指定
env :PATH, ENV['PATH']

# ログファイルの出力先
set :output, 'log/cron.log'

# ジョブの実行環境の指定(実行環境はprodaction環境がデフォルト設定)
set :environment, :development

# 日本時間の午前8:00にメール送信される（JSTは+9:00なので-9:00の時間を記述）
# 未読通知が3件以上たまっているユーザーにメール通知
every 1.days, at: '11:00 pm' do
  runner "ScheduledProcessingMailer.check_notice_mail.deliver_now"
end
```
今回は日本時間の午前8:00にメール送信される設定にしました。最初はデバックのために下記のようにして確かめてもいいと思います。

```
every 1.minutes do
   runner "ScheduledProcessingMailer.check_notice_mail.deliver_now"
end
```

* schedule.rbの変更をcronに登録

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

* 反映されているか確認

```
crontab  -l 
```
ScheduledProcessingMailer.check_notice_mailに記載があれば登録されています

* ログはlog/cron.logにから確認できます

### =>これでメール送信されるはずです！！

<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/642283/f4ae0b49-d36f-7192-1128-f76bd30cc2f5.jpeg" width=30%>

* バッチ処理を停止したい場合(cronの中を空にする)

```
bundle exec whenever --clear-crontab
```

* 反映されているか確認

```
crontab  -l 
```
空になっていたらOK