ActionMailer、Rakeタスク、wheneverで作るメール自動配信機能

#目標
管理者ユーザーに毎朝8時に総記事数、昨日投稿された記事情報を送る機能を実装します。
#実装
実装の手順は
1. Mailerの作成
2. メールを送信できるか確認
3. RakeタスクにMailerの処理を登録
4. wheneverで定期実行 
それでは行こう！

## 1. Mailerの作成
まずMailerを作成します。
コマンドで実行してもいいですが今回は手動でファイルを追加していきます。
`app/mailers/`にファイルを作成します。


```ruby:ターミナル 
$　touch app/mailers/admin.mailer.rb #命名は自由
```

作ったファイルは`ApplicationMailer`を継承させメソッドを定義します。
このメソッドはMVCのControlerとViewの考え方と同じように一つ一つに送るメール内容であるViewが存在します。
今回は全体の記事数と昨日の記事情報の変数を定義しています。

```ruby:app/mailers/admin.mailer.rb
class AdminMailer < ApplicationMailer
  
  def report
    @article_count = Article.count
    @article_published_yesterday = Article.where(created_at: 1.day.ago.all_day)
    mail(to:'admin@example.com', subject: '[定期連絡] 昨日の記事の集計結果')
  end
end
```

```ruby
 mail(to:'admin@example.com', subject: '公開済記事の集計結果')
```
ここの部分はメールを送る相手のメールアドレスとメールの件名部分になります。

続いてメール本文部分のViewを作ります。

```ruby:ターミナル 
$　mkdir app/views/admin_mailer
$　touch app/views/admin_mailer/report.html.erb
```

作成したファイルにメール本文を入力します。

```ruby:app/views/admin_mailer/report.html.erb
<p>総記事数: <%= @article_count %></p>
<% if @article_published_yesterday.present? %>
  <% @article_published_yesterday.each do |article| %>
    <p>タイトル: <%= article.title %></p>
    <p>投稿者: <%= article.user.name %></p>
  <% end %>
<% end %>
```
これでmailer部分は完成です。

## 2. メールを送信できるか確認
mailerができたので実際にメールを送れるのかを確認します。
確認方法は`letter opener`というgemを使っていきます。
Gemfileに以下を追記して`bundle install`

```ruby:Gemfile
group :development do
  gem 'letter_opener'
  gem 'letter_opener_web', '~> 1.0'
end
```

```ruby:ターミナル 
$　bundle install
```

インストールできたら設定をしていきます。
以下を追加してください。
設定に関しては公式通りなので説明は特にしません。

```ruby:config/environments/development.rb 
config.action_mailer.delivery_method = :letter_opener_web
config.action_mailer.perform_deliveries = true
```

```ruby:config/routes.rb 
 mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
```
ここまでできたらサーバーをたちあげて`http://localhost:3000/letter_opener`にアクセスしてください
以下のような画面がでできたらOKです。
![スクリーンショット 2021-07-01 11.01.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/974719/809dd02f-104d-f27c-6c1b-6b1bbd44d043.png)

ここで送られてきたメールの内容を見ることができます。

それではメールを送っていきましょう。
コンソールを立ち上げます。

```ruby:ターミナル 
$　rails c
```
`deliver_now`というメソッドを使うことでメールを今すぐに送信してくれます。

```ruby:ターミナル 
irb(main):001:0> AdminMailer.report.deliver_now
```

ここでまたletter_openerを確認してメールが送られてきてたらOKです！

## 3. RakeタスクにMailerの処理を登録
メールが送れることを確認できたらメール送信の処理をRake タスクに登録していきます。
ターミナルでタスクを作成します。

```ruby:ターミナル 
$　rails g task article_report
```

作成されたタスクファイルにメール送信処理を登録します。

```ruby:lib/task/article_report.rake
namespace :article_report do
  desc '管理者に総記事数、昨日投稿された記事のタイトルと投稿者をメール送信' #解説
  task mail_article_report: :environment do  #タスク名
    AdminMailer.report.deliver_now #実行したい処理
  end
end
```

Rakeタスクからメールが送れるかを確認していきましょう。

```ruby:ターミナル 
$　rake -T
```
表示されているかを確認して表示されていれば実行していきます。

```ruby:ターミナル 
$　rake article_report:mail_article_report
```

ここでまたletter openerを確認して送信されていればOKです。


## 4. wheneverで定期実行 
最後にwheneverを使ってメール送信の処理を定期実行できるようにしていきましょう！

gemをインストール。

```ruby:Gemfile
gem 'whenever', require: false
```

```ruby:ターミナル 
$　bundle install
```
インストールできたら設定ファイルをインストールしていきます。

```ruby:ターミナル 
$ bundle exec wheneverize .

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

ここで`schedule.rb`というファイルが作成されるのでそこに設定を書いていきます。

```ruby:config/schedule.rb
require File.expand_path(File.dirname(__FILE__) + '/environment')
# cronを実行する環境変数
rails_env = ENV['RAILS_ENV'] || :development
# cronを実行する環境変数をセット
set :environment, rails_env
# cronのログの吐き出し場所
set :output, "#{Rails.root}/log/cron.log"

# 時間指定
every 1.minutes do
  rake 'article_report:mail_article_report'
end
```

```ruby
every 1.minutes do
  rake 'article_report:mail_article_report'
end
```
この部分にrakeタスクで登録した処理を書きます。
最初は実際に動いているかを確認するために1分毎にメールを送信することにします。

ターミナルでコマンドを入力することで反映されます。

まずエラーがないかを確認するので以下を入力
登録したRakeタスク名が入っていればOKです。

```ruby:ターミナル 
$ bundle exec whenever 
```

次に現在設定されているcronを確認するために以下を入力
最初なので何も表示されないはずなのでそれでOK

```ruby:ターミナル 
$ crontab -l
```
そしたら設定を反映していきます。
以下を入力することで設定が反映されます

```ruby:ターミナル 
$ bundle exec whenever --update-crontab 
```
反映されているかを確認するためにもう一度以下を入力
以下のような表示があれば設定が反映されています。

```ruby:ターミナル 
$ crontab -l

# Begin Whenever generated tasks for:...
# End Whenever generated tasks for:...
```
設定が反映されているのを確認できたら
実行状況を確認していきます。
ログファイルを開いて

```ruby:log/cron.log
/usr/bin/open file:////Users/asahi/Desktop/review/tmp/letter_opener/1625029929_4833531_b61109f/rich.html
```
のような記述があればOKです。
実際にletter openerでも確認しましょう。

確認ができたらこのまま1分毎にメール送信されるのは邪魔なので設定を変更していきます。
以下のコマンドでcronからデータを削除します。

```ruby:ターミナル 
$ bundle exec whenever --clear-crontab
```
実際に削除されているかを確認するために

```ruby:ターミナル 
$ crontab -l
```
を実行して何も表示がされなかったらOKです。

それでは`schedule.rb`に毎朝8時にメールが届くように設定を書き換えていきます。

```ruby:config/schedule.rb
# Rails.rootを使用するために必要
require File.expand_path(File.dirname(__FILE__) + '/environment')
# cronを実行する環境変数
rails_env = ENV['RAILS_ENV'] || :development
# cronを実行する環境変数をセット
set :environment, rails_env
# cronのログの吐き出し場所
set :output, "#{Rails.root}/log/cron.log"

# 時間指定
every 1.day, at: '8am' do #変更場所
  rake 'article_report:mail_article_report'
end
```

```ruby:ターミナル 
$ bundle exec whenever --update-crontab 
```

ターミナルで反映したら完成です！


#エラー対応
log/cron.logで`Operation not permitted`というエラーが出た方は(自分は出た)以下の記事が役立ったので参考にしてください。

https://mac-ra.com/catalina-crontab/

https://qiita.com/nishina555/items/b8b0800800ccb46333af