Rails 通知メールを送信する

# はじめに
今回Xクローンの実装にてメールにて通知を送る機能の実装をしたので、自分自身の備忘録として、また今後実装する方のお役に立てればと思いこちらの記事を書くことにしました。

# メール機能の作成
要件として、`いいね` `リポスト` `コメント` `フォロー`をされた場合、web上の通知画面とともにメールを送信して通知をお知らせする機能を実装する。

※前提としてSendGridとletter_opener_webを使用できる状態であること。

# メールを送信する
#### メーラーを作成する
```
rails g mailer User
```

#### ルーティングの設定
これは開発環境で使用するルーティングになります。
```ruby:routes.rb
mount LetterOpenerWeb::Engine, at: '/letter_opener' if Rails.env.development?
```

#### サーバーの設定
メールを送信するときは、送信するサーバーが必要。と言うことで、メール送信設定を記述します。

**開発環境**
```ruby:development.rb
config.action_mailer.default_url_options = { host: 'localhost:3000' }
config.action_mailer.default_options = { from: 'from@example.com' }
config.mailer_sender = 'please-change-me-at-config-initializers-devise@example.com'
config.action_mailer.delivery_method = :letter_opener_web
```

**本番環境**
```ruby:production.rb

  config.action_mailer.perform_caching = false
  config.action_mailer.perform_deliveries = true
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.default_url_options = { host: 'https://herokuのアプリ名.herokuapp.com/' }
  # SENDGRID用
  config.action_mailer.smtp_settings = {
    address: 'smtp.sendgrid.net',
    port: 587,
    domain: 'heroku.com',
    user_name: 'apikey',
    password: ENV['SENDGRID_APIKEY'],
    authentication: :plain,
    enable_starttls_auto: true
  }
  config.action_mailer.default_options = { from: ENV['SENDER_ADDRESS'] }
  config.mailer_sender = ENV['SENDER_ADDRESS']
```
上記の`ENV`の部分はHerokuの環境変数として設定しています。

#### mailerの書き方（メール送信メソッドの実装）
```ruby:application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: 'from@example.com'
  layout 'mailer'
end
```

```ruby:user_mailer.rb
class UserMailer < ApplicationMailer

  def like_notification(user, post)
    @user = user
    @post = post
    mail(to: @post.user.email, subject: 'いいねがありました')
  end

  def repost_notification(user, post)
    @user = user
    @post = post
    mail(to: @post.user.email, subject: 'リポストがありました')
  end

  def comment_notification(user, post, comment)
    @user = user
    @post = post
    @comment = comment
    mail(to: @post.user.email, subject: 'コメントがありました')
  end

  def follow_notification(user, following)
    @user = user
    @following = following
    mail(to: @user.email, subject: 'フォローされました')
  end
end
```

`いいね` `リポスト` `コメント` `フォロー`の各アクションごとにメソッドを作成しています。

#### メール送信のトリガー設定
送信のトリガーとなるメソッドを実装していきます。
**いいね**されたとき
```ruby:likes_controller.rb
def create
    @post = Post.find(params[:post_id])
    @like = current_user.likes.new(post_id: @post.id)
    @like.save
    @post.create_notification_like!(current_user)
    # ここから
    UserMailer.like_notification(@like.user, @post).deliver_now
    # ここまで追加
    redirect_to request.referer
  end
```

**リポスト**されたとき
```ruby:reposts_controller.rb
  def create
    if current_user.reposts.find_by(user_id: current_user.id, post_id: @post.id)
      redirect_to root_path, alert: '既にリポスト済みです'
    else
      @repost = current_user.reposts.create(user_id: current_user.id, post_id: @post.id)
      redirect_to request.referer, notice: 'リポストしました'
      @post = Post.find(params[:post_id])
      @post.create_notification_repost!(current_user)

      # ここから
      UserMailer.repost_notification(@repost.user, @post).deliver_now
      # ここまで追加
    end
  end
```

**コメント**されたとき
```ruby:commetnts_controller.rb
  def create
    @post = Post.find(params[:post_id])
    @comment = @post.comments.build(comment_params)
    @comment.user = current_user
    @comment.save
    @post.create_notification_comment!(current_user, @comment.id)

    # ここから
    UserMailer.comment_notification(@comment.user, @post, @comment).deliver_now
    ＃ここまで追加
    redirect_to request.referer
  end
```

**フォロー**されたとき
```ruby:relationships_controller.rb
  def create
    @user = User.find(params[:user_id])
    following = current_user.relationships.build(follower_id: params[:user_id])
    following.save
    @user.create_notification_follow!(current_user)
    # ここから
    UserMailer.follow_notification(@user, current_user).deliver_now
    # ここまで追加
    redirect_to request.referer
  end
```

#### メールのviewの作成
今回viewもアクションごとに実装していきます。
お知らせの通知なので、とてもシンプルなメールの内容になっています。

**いいね**されたとき
```like_notification.html.slim
div
  h1
    | いいねがありました！
  p
    | #{@user.name}さんがあなたのポストにいいねしました。
```

**リポスト**されたとき
```repost_notification.html.slim
div
  h1
    | リポストされました！
  p
    | #{@user.name}さんがあなたのポストをリポストしました。
    
```

**コメント**されたとき
```comment_notification.html.slim
div 
  h1 
    | コメントがありました！

  p
    | #{@user.name}さんがあなたのポストにコメントしました。

  p 
    | コメント内容
  br
    | #{@comment.comment_content}
```

**フォロー**されたとき
```follow_notification.html.slim
div
  h1
    | フォローされました！
  p
    | #{@following.name}さんがあなたをフォローしました。

```

実際に送られてきたメールはこんな感じです。
![スクリーンショット 2024-03-15 22.32.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3335067/311e400d-4559-14ed-8f74-9929ad9e3c4d.png)

しっかりsendgrid経由でメールが送られてきています。


# 最後に
これで、メールでの通知機能の実装も終わりました。メールの実装はそこまで難しいところもなく思ったよりスムーズに実装することができました。


# 参考サイト
https://zenn.dev/ebina_shohei/articles/6c3b325a361f19

https://plog.kobacchi.com/heroku-sendgrid-email-authentication/

https://qiita.com/annaaida/items/81d8a3f1b7ae3b52dc2b

https://qiita.com/sazumy/items/e0e9f1aaeed47c616c6b