Rails グループメンバーにメールを送信する「Action Mailer」

# Rails　Action Mailrを利用してグループメンバーにメールを送信する機能の実装方法
こんにちは！
Rails初学者の私ですが、先日グループ機能を応用してのAction Mailerを利用した
グループメール送信機能を実装しましたので
その実装方法を記事にしてみました。

## 今回やること
グループメンバーの一人からグループメンバー全員にメールを送れる。
メール送信後は送信完了画面を表示する。

## 前提
- グループ機能が実装済み
- Deviceでuserログインができる
グループ機能の実装方法が分からない場合は
以前に実装方法の記事を作成しましたので下記を参考にしてみて下さい。
https://qiita.com/fumiya1800/items/ec1b2f4d94c74ef041c7
https://qiita.com/fumiya1800/items/ec114e548a7e043f7752

## 完成系のイメージ
<img width="400" alt="スクリーンショット 2023-06-15 14.03.12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3398256/3af84bba-7737-36af-5606-03da0c168489.png">

送信ボタンを押すとグループメンバー全員にメールが送られて、
送信完了画面に遷移します。
<img width="400" alt="スクリーンショット 2023-06-15 14.03.58.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3398256/61f89f39-cf06-8e13-e41d-80f900be9aa4.png">

## メイラーを作成する
```
$ rails generate mailer EventMailer
```
このようにapp/mailers内にevevt_mailer.rbが作成されておりますでしょうか。
application_mailer.rbは元々あるものです。

<img width="200" alt="スクリーンショット 2023-06-15 14.11.36.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3398256/f41b5672-4842-c6e9-29c5-60b6a10109aa.png">

## メールサーバーの設定
Gmailを使って送信できるように設定をしていきます。

```config/environments/development.rb
config.file_watcher = ActiveSupport::EventedFileUpdateChecker
config.action_mailer.raise_delivery_errors = true
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
  port:                 587,
  address:              'smtp.gmail.com',
  domain:               'gmail.com',
  user_name:            'Gamilのアドレス',
  password:             'アプリパスワード',
  authentication:       'login',
  enable_starttls_auto: true
}

```

development.rbファイルにこの記述を追加します。

それぞれがどういう意味なのかは以下の記事がとても参考になります。
https://qiita.com/annaaida/items/81d8a3f1b7ae3b52dc2b

※アプリパスワードとはGamilの16桁のパスワードになります。
以下のやり方でやっていただければ上手くいくと思います。
簡単にいうと、
①Googleアカウト→セキュリティのGoogleでのログインで２段階プロセスをONにします。
②その後、アプリパスワードというものを設定できるようになるので、そこでアプリパスワードを設定します。
最初、アプリパスワード設定の画面が見つからず、違うやり方を試みたのですが、できませんでした。
２段階プロセスをONした後に、Googleアカウト→セキュリティのGoogleでのログインを見れば、アプリパスワードの設定ができるかと思います。

:bangbang:ちなみに、メールアドレスとパスワードをgithubにプッシュしないようにして下さい。
メールアドレスとパスワードは環境変数を使って、情報漏洩を防ぎます。
環境変数の設定方法の記事も作成しましたので、参考にしてみて下さい。
https://qiita.com/fumiya1800/items/6795e5e1046ec6f60aed

## メーラーを編集する
application_mailer.rbには、どのメーラーにも共通することを記述していきます。
```app/mailers/application_mailer.rb
class ApplicationMailer < ActionMailer::Base
  default from: '管理人<from@example.com>'
  layout 'mailer'
end

```


```app/mailers/event_mailer.rb
class EventMailer < ApplicationMailer

  # 下のクラスメソッド内で使用するメソッド
  # このメソッド（アクション）が発動するとviews/event_mailer/send_notification.text.erbを呼出して、
  # メールを引数のデータに従ってメールを作成する。
  def send_notification(member, event)
    @group = event[:group]
    @title = event[:title]
    @body = event[:body]

    #メールを新規作成
     #from→送り主、to→送り先、subject→メールタイトルを入力
    @mail = EventMailer.new()
    
    mail(
      from: 'Gmailアドレス',
      to:   member.email,
      subject: '新規お知らせ'
    )
  end

  #　このクラスメソッドが呼出されるとメールをグループメンバにメールを送信する
  # フォームでメールを送信を押したタイミングで発動(event_noticesコントローラの#create呼出時)
  def self.send_notifications_to_group(event) #引数のeventはevent_noticesコントローラでハッシュでデータを入れている
    group = event[:group] #group_idを呼出
    group.users.each do |member| #group_idに紐づくuserを順番に取り出す
      # 上のメソッドを発動すると各メンバー毎にメールが作られて、.deliver_nowで送信をしている
      EventMailer.send_notification(member, event).deliver_now
    end
  end
end

```
event_mailer.rbで記述したメソッドは次に作成するコントローラーで使用していきます。
後に紐づきが理解できるかと思いますので安心して下さい。

## event_noticesコントローラーを作成
```
$ rails g controller public/event_notices
```
### コントローラーを編集する
```app/controllers/public/event_notices_controller.rb
class Public::EventNoticesController < ApplicationController
  before_action :authenticate_user!

  def new
    # view/event_notices/new.html.erbのフォームでグループIDが必要な為
    @group = Group.find(params[:group_id])
  end

  def create
    @group = Group.find(params[:group_id]) #newアクションと同じグループIDが入っている
    @title = params[:title] #フォームで入力された内容が入っている
    @body = params[:body] #フォームで入力された内容が入っている

    # 上記でインスタンス変数のデータを変数eventのハッシュとして登録
    event = {
      #キー　=> 　データ
      :group => @group,
      :title => @title,
      :body => @body,
      # enent[:group]のように呼び出すと@groupを呼び出せるようになる（event_mailerで使う）
    }
    
    #app/mailers/event_mailer.rbのメソッドを使用している
    EventMailer.send_notifications_to_group(event)
    # @group,@title,@bodyのデータを持ったまま、view/event_notices/sent.html.erbを表示する
    render :sent
  
  end

  def sent
    redirect_to group_path(params[:group_id])
  end

end
```

解説します。
newアクションではどのgroupのメールなのかを判断する為に
`@group` = Group.find(params[:group_id])を定義しています。

createアクションではview上のフォームに入力された内容を
変数名eventにハッシュとして格納しています。
これによって、enent[:group]のように呼び出すと
フォームに入力された`@group`の内容を呼び出すことが可能となります。

そしてevent_mailer.rbに記述した
self.send_notifications_to_group(event)メソッドを
EventMailer.send_notifications_to_group(event)として使用しています。
このeventにはフォームに入力された内容がハッシュとして入っています。

コントローラー側の処理は以上で
最後にsent.html.erbページをrenderで表示しています。

EventMailer.send_notifications_to_group(event)を呼出し後は
event_mailer.rb内で処理が進んでいきます。
event_maile.rb内の処理の説明は上記の該当箇所で細かくコメントを残していますので
確認してみて下さい。


##  ルーティングの編集
 ```config/routes.rb
scope module: :public do
    resources :groups, except: [:new] do
      resource :permits, only: [:create, :destroy]
      resource :group_users, only: [:create, :destroy]
      resources :event_notices, only: [:new, :create] #追加
      get "event_notices" => "event_notices#sent" #追加
    end
    get "groups/:id/permits" => "groups#permits", as: :permits
end

```


## viewページを作成
メール作成ページになります。
```app/views/public/event_notices/new.html.erb
<div class="container">
  <h2 class="text-center">メール作成</h2>

  <div class="row mt-5">
    <div class="col-10 col-md-7 mx-auto">
      <%= form_with url: group_event_notices_path(@group), method: :post, local:true do |f| %>
        <div class="form-group">
          <%= f.label :title, 'タイトル' %>
          <%= f.text_field :title, class: 'form-control' %>
        </div>
        <div class="form-group">
          <%= f.label :body, '本文' %>
          <%= f.text_area :body, rows: 10, class: 'form-control' %>
        </div>
        <div class="form-group d-flex justify-content-end">
          <%= f.submit "送信", class: 'btn btn-success' %>
        </div>
      <% end %>
    </div>
  </div>

  <div class="row mt-5">
    <div class="col-md-9 mx-auto">
    <p class="text-center"><%= link_to "戻る", group_path(@group.id), class: 'text-dark' %></p>
    </div>
  </div>

</div>

```

次にメール送信完了ページです。
```app/views/public/event_notices/sent.html.erb
<div class="container">
  <div class="row justify-content-center">
    <div class="col-6">
      <h1>送信が完了しました</h1>
      <p>内容は以下の通りです。</p>
      <h2>[タイトル]</h2>
      <p><%= @title %></p>
      <h2>[本文]</h2>
      <p><%= @body %></p>
    </div>
  </div>
</div>
```

グループ詳細ページにメール作成ページへ遷移するリンクを追加します。
```app/views/public/groups/show.html.erb
<%= link_to 'グループメール', new_group_event_notice_path(@group), class: "btn btn-outline-info btn-sm" %>
```

## メールの本文ページを作成する
このページ内容でGmailは作成されることになります。
ファイル名はevent_mailer.rb内のメソッド名と同じにします。

```app/views/event_mailer/send_notification.html.erb
<!DOCTYPE html>
<html>
  <head>
    <meta content='text/html; charset=UTF-8' http-equiv='Content-Type' />
  </head>
  <body>
    <h2>お知らせ from <%= @group.name %></h2>
    <p>
      ＜タイトル＞<br>
      <%= @title %>
    </p>
    <p>
      ＜内容＞<br>
      <%= @body %>
    </p>
  </body>
</html>
```

以上でメール機能は完成となります。！！
ちなみにメールはテキスト形式での作成可能です。
今回はHTML形式で作成しています。

実装は以上になります。

## 最後に
最後までご覧いただきありがとうございます。
初学者なので、間違っていることや、分かりづらい箇所もあるかと思います。
何かお気づきがあれば遠慮なくご指摘頂けると幸いです。

ここまで長くなりましたが
最後までお付き合いいただきましてありがとうございました！！