【Ruby on Rails】ActionMailerを使用した問い合わせ機能の実装（初学者向け）

#実装機能
問い合わせフォームからメールを送信、それを指定したメールアドレスで受信する。
（アプリの利用者から管理者に向けてのメール機能として実装）

ActionMailerでは他にもメルマガ配信のように運営側からユーザーに対してメール送信を行ったり、問い合わせに対するメールの返信機能なども実装が可能とのことだが、今回は一番シンプルなこちらの機能を実装。
またGmailアカウントでのメールの受信方法の為、前提としてGmailのアカウントを持っている体で話を進めていく。

##**完成イメージ**

![スクリーンショット 2021-01-24 18.46.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/936377/cbdf89fd-9cbb-aa56-9722-7a8d59f6bfdb.png)

#実装内容
##1.コントローラの作成
使用するビューファイルはnewのみな上にルーティングの修正が面倒な為、アクションの指定はせずにコントローラファイル単体で作成。

```
$ rails g controller inquiries
```

##2.ルーティングの作成

今回使用するアクションは以下の2つ
・問い合わせ作成画面に使用する`newアクション`
・問い合わせのデータを作成する為の`createアクション`

```rb:config/routes.rb
resources :inquiries, only[:new, :create] 
```
##3.モデルの作成

最低限必要な情報としてユーザーの名前とメッセージ内容を保存するカラムを用意するが、今回は送信したユーザーが問い合わせに関して返答を要求する場面を想定し、emailのカラムも作成しておく。

```
$ rails g model Inquiry name:string email:string message:text
```
マイグレーションファイルに特に変更がなければ `bundle install`を実行してテーブルを作成。

その後必要なカラムにバリデーションをかけておく。

```rb:app/models/inquiry
class Inquiry < ApplicationRecord
  validates :name, presence: true
  validates :email, presence: true
  validates :message, presence: true
end
```

##4.Mailerの作成

ActionMailerという機能がRailsに標準搭載されており、下記のコマンドで作成が出来る

```terminal:terminal
$ rails g mailer inquiry 
```

以下のファイルが作成されるのを確認

```terminal:terminal
create  app/mailers/inquiry_mailer.rb
invoke  erb
create    app/views/inquiry_mailer
invoke  test_unit
create    test/mailers/inquiry_mailer_test.rb
create    test/mailers/previews/inquiry_mailer_preview.rb
```
このうちの`inquiry_mailer.rb`は、メール送信機能を実装するための空のクラス

##5.Mailerにメソッドを定義

`InquiryMailer`内でメソッドを定義する。
ここで定義したメソッドを実際にデータの作成、送信を実行する`Inquiriesコントローラ`内で使用する

```rb:app/mailers/inquiry_mailer.rb
class InquiryMailer < ApplicationMailer

  def send_mail(inquiry)
    @inquiry = inquiry
    mail to: 'メールアドレス', subject: '【サイト名】お問い合わせ通知'
  end
end
```
上記の**mailメソッド**で指定されているプロパティの内容は以下の通り
・`to = 送信先（メールアドレス）の指定`
・`subject = メールの件名`

要はここで指定したアドレスから指定した件名でメールが届くということなる。

##6.コントローラにメソッドを定義

```rb:app/controllers/inquiries_controller.rb
class InquiriesController < ApplicationController

  def new
    @inquiry = Inquiry.new
  end

  def create
    @inquiry = Inquiry.new(inquiry_params)
    if @inquiry.save
      InquiryMailer.send_mail(@inquiry).deliver 
      redirect_to new_inquiry_path
      flash[:email] = "Your message was successfully sent."
    else
      render 'new'
    end
  end

  private

  def inquiry_params
    params.require(:inquiry).permit(:name, :email, :message)
  end
end
```
アクション内の処理の流れは通常の投稿作成とほぼ同じだが、createアクション内の処理で先程作成した`InquiryMailer`のメソッドを使用する。

```rb
InquiryMailer.send_mail(@inquiry).deliver 
```
コードの文末にある**deliverメソッド**はメールの送信に関わるメソッドになる。
因みに、当然の事ながらこの行の処理が完了するまで以降のredirect等の処理が行われない為、フラッシュメッセージが現れるまで数秒間掛かることもある。
それを回避する為に`ActiveJob`と連携して非同期にメール送信を行う為の**deliver_later**というメソッドも存在するらしいが、今回はこちらを採用。

##7.development.rbにメール送信設定を記述する

ドメインの指定等の設定をconfigディレクトリ配下のdevelopment.rbファイルに記述する。

```rb:config/environment/development.rb
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    address: 'smtp.gmail.com',
    port: 587,
    domain: 'gmail.com',
    user_name: 'メールアドレス',
    password: 'パスワード',
    authentication: 'plain',
    enable_starttls_auto: true
  }
```
このあたりはこちらの参考記事の説明がわかりやすかったのでそのまま引用させて頂くことにする。

>ここでは、config.action_mailerというパラメーターに色んなオプションを指定してます。
>1行目 raise_delivery_errors
メールの送信に失敗した時にエラーを出すかどうか （出したいので true）

>2行目 delivery_method
メールの送信方法。 デフォルトで :smtd なので気にする必要もないのですが、
わたしみたいに「なにそれ！？」ってなった方は以下の引用を読んでみてください。

>>「SMTP」とは「Simple Mail Transfer Protocol（シンプル・メール・トランスファー・プロトコル）」の略で、あえて>訳せば「簡単なメールの送信の手順」というところだろうか。お約束ごとと考えてもいい。

>>あなたがメールを書き、宛先のアドレスを入力して「送信」アイコンをクリックする。このとき、あなたのスマホやパソコン>は、この「SMTP」のお約束ごとに従って、あなたが契約しているメールサーバーと、こんなやり取りをするのである。
>>「メールを送るよ〜」「ええで！」「宛先は〇◯だよ」「りょ」「本文はかくかくしかじかだよ」「受け取ったで！」――とまぁそんな具合。

>出典： メール設定で最初につまずく「SMTP」「POP」「IMAP」。その意味＆設定方法は？

>3行目 smtp_settings
smtpの詳細設定って感じです。

>port => SMTPサーバーのポート番号
address => SMTPサーバーのホスト名
domain => HELOドメイン
user_name => メール送信に使用するgmailのアカウント
password => メール送信に使用するgmailのパスワード
authentication => 認証方法
enable_starttls_auto => メールの送信にTLS認証を使用するか

#####※前項のMailerやここで使用するメールアドレスやパスワードは`Github`にpushする際には環境変数化しておく必要があるので注意
#####また、本番環境でアプリケーションを運用する場合は、`produciton.rb`にも同じ内容を記述する必要がある。


##8.ビューを作成する

問い合わせフォーム用のビュー画面を作成する。
コードは冒頭で添付した画面で使用したものなので、ご自身のアプリに合わせて作成。
通常のフォーム画面の作成と変わらないはず。

```erb:app/views/inquiries/new.html.erb
:
  <div class="contact_form text-center">
    <%= form_with model: @inquiry, local:true do |f| %>
    <%= render 'layouts/error_messages', model: f.object %>
      <h3>NAME</h3>
      <%= f.text_field :name %>
      <h3>EMAIL</h3>
      <%= f.email_field :email %>
      <h3>MESSAGE</h3>
      <%= f.text_area :message %>
    <div>
      <p><%= f.submit "送信" %></p>
    </div>
    <% end %>
  </div>
:
```
##9.メール画面を構成するファイルを作成

上記とは別に実際に送られてくるメールのレイアウトを構成するファイルも作成する必要がある。
**ActionMailer**のコマンドを実行した際に`viewsディレクトリ`の中に`inquiry_mailerディレクトリ`が作成されているため、そこにファイルを作成する。
今回はアプリの管理者が受け取る想定の為、構成には必要最低限しか気を配っていない。

因みに場合によってはHTML形式のメールを受け取ることができない場合もあるらしく、そのためテキスト形式のファイルも用意しておくのがベスト。

**HTML形式**

```erb:app/views/inquiry_mailer/send_mail.html.erb
<h5>お問い合わせ内容</h5>

<P>-----------------------------------------</P>

<p>名前：<%= @inquiry.name %></p>

<p>メールアドレス：<%= @inquiry.email %></p>

<p>お問い合わせ内容：<%= @inquiry.message %></P>

<p>-----------------------------------------</p>

```
**テキスト形式**

```text:app/views/inquiry_mailer/send_mail.text.erb
お問い合わせ内容

-----------------------------------------

名前：<%= @inquiry.name %>

メールアドレス：<%= @inquiry.email %>

お問い合わせ内容：<%= @inquiry.message %>

-----------------------------------------
```

実際に届くメール画面がこちら（HTML形式）

![スクリーンショット 2021-01-24 21.22.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/936377/228bcc8d-06dd-1c97-9980-b35affbb55e9.png)

##10.環境変数を使用

Githubにpushしたり、本番環境でアプリを使用する際はこれまでに使用したメールアドレスやパスワードはセキュリティを考慮し環境変数化しておく必要がある。
gemの`dotenv-rails`をinstallしている前提での説明な為、gemをインストールしていない場合は導入する。

`.envファイル`に実際のメールアドレスやパスワードを記述

```rb:.env
SEND_MAIL="使用するメールアドレス"
GMAIL_PASSWORD="使用するGmailアカウントのパスワード"
```
定義した環境変数をコード内で使用

```rb:app/mailers/inquiry_mailer.rb
:
    mail to: ENV['SEND_MAIL'], subject: '【サイト名】お問い合わせ通知'
:
```
```rb:config/environment/development.rb
:
    user_name: ENV['SEND_MAIL'],
    password: ENV['GMAIL_PASSWORD'],
:
```

`.envファイル`を`.gitignoreファイル`に記述して完了

##補足
gmailのアカウントの設定の関係でアクション実行の際に以下のようなサーバーエラーが発生する可能性がある。

・`Net::SMTPAuthenticationError (535-5.7.1 Username and Password not accepted. Learn more at`
・`Net::SMTPAuthenticationError 534-5.7.9 Application-specific password required.`

上記エラーが現れた際は、別途Gmailアカウントの設定変更が必要となる可能性が高い（パスワードやメールアドレスのスペルミス等の可能性もあるため、まずはそこを疑う）。
個人的には実装よりもむしろこれらのエラーの解消に手こずったので、参考になれば。

##参考記事
**ActionMailer参考記事**
・[Action Mailer でメール送信機能をつくる](https://qiita.com/annaaida/items/81d8a3f1b7ae3b52dc2b)
・[【Rails入門説明書】Action Mailerについて解説]
(https://web-camp.io/magazine/archives/19143)
 **サーバーエラーの解決のために使用**
・[Googleで2段階認証を使っているときにRailsのActionMailerでGmailを使う方法](https://qiita.com/katryo/items/6dedbad8044428c13b84)
・[[Rails5]deviseでgmailを送ろうとしたがsmtp認証のエラーが出た時にした事。](https://qiita.com/k-kou5/items/1ed178680a3a45c1edf7)