【Rails】ActionMailerでお問合せフォームを作ろう！！

# はじめに
お問合せフォームをActionMailerを使って実装する方法を調べ、実装した。

**完成予想図**
以下のようなものを作る。
①お問合せフォームの作成
![スクリーンショット 2022-08-09 22.46.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/b96d1935-4119-26e2-bcca-33416e39bbc6.png)
②確認画面の作成
![スクリーンショット 2022-08-09 22.46.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/8b1bb9c0-bf79-b113-c6af-a7f32dfa9f32.png)
③送信後、ホームへリダイレクト
![スクリーンショット 2022-08-09 22.43.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/22701555-2837-decd-3f63-5b5161681374.png)
④メールで確認
![スクリーンショット 2022-08-09 22.49.00.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/ad3f0e21-8ca6-c529-e6e3-e9a69b942ace.png)


# 前提

| No |    項目     |   内容    |
|---:|-------------|------------|
| 1  |      OS       |   Mac     |
| 2  |       Ruby      |   2.6.3   |
| 3  |       rails      |      6.0.4 |


# 実装

https://qiita.com/japwork/items/145645e281b81d9bf92c

上記の内容を参考にした。

# modelの作成
名前、メールアドレス、問い合わせ内容というカラムのあるモデルを作成する。
```言語名:ターミナル
# モデル名はcontactなどそれぞれ好きなものを作成すること
$ rails g model staticpage name:string email:string content:text
```
以下のマイグレーションファイルも作成されたことを確認する。
```db/migrate/<timestamp>_create_staticpages.rb
class CreateStaticpages < ActiveRecord::Migration[6.0]
  def change
    create_table :staticpages do |t|
      t.string :name
      t.string :email
      t.text :content

      t.timestamps
    end
  end
end
```
**モデルにバリデーションを設定**
下記の内容でバリデーションをかける。
>・名前、メールアドレス、内容が空欄でないこと
・名前、メールアドレス、内容の文字数制限
・メールアドレスの正規表現の制限

入力画面で上記のことを守れていないと、エラーが起きる。
```staticpage.rb
class Staticpage < ApplicationRecord

  validates(:name,  presence: true, length: { maximum: 50  })
  VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-]+(\.[a-z\d\-]+)*\.[a-z]+\z/i
  validates(:email, presence: true, length: { maximum: 255 },
                    format: { with: VALID_EMAIL_REGEX },
                    uniqueness: true)
  validates :content, presence: true, length: { maximum: 500 }

end

```

# routesの設定
ルーティングの設定をする。
下図のような流れで動作するようにする。
![スクリーンショット 2022-08-10 0.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/0975b0f0-2c9c-3672-a144-38378efdeb11.png)
postリクエストで、入力情報を次のステップに送ることで、それぞれの画面で情報を取り扱っていく。

```routes.rb
  get  '/contact', to: 'staticpages#contact'
  post '/confirm', to: 'staticpages#confirm', as: 'confirm'
  post '/back',    to: 'staticpages#back' ,   as: 'back'
  resources :staticpages, only: [:create]
```

# controllerの設定
先ほどの図を実現するため、コントローラーの設定をする。
```staticpages_controller.rb
  def contact
    @contact = Staticpage.new
  end

  # contactアクションから入力内容を受け取り、
  # 送信ボタンを押されたらcreateアクションを実行します。
  def confirm
    @contact = Staticpage.new(contact_params)
    # if @contact.invalid?
    #   render :contact
    # end
  end

  # 入力内容に誤りがあった場合、
  # 入力内容を保持したまま前のページに戻るのが当たり前になっているかと思いますが、
  # backアクションを定義することで可能となります。
  def back
    @contact = Staticpage.new(contact_params)
    render :contact
  end

  # 実際に送信するアクションになります。
  # ここで初めて入力内容を保存します。
  # セキュリティーのためにも一定時間で入力内容の削除を行ってもいいかもしれません。
  def create
    @contact = Staticpage.new(contact_params)
    if @contact.save
      UserMailer.contact(@contact).deliver_now
      flash[:success] = "お問合せが送信されました。"
      redirect_to root_url
    else
      render :contact
    end
  end

  private

  def contact_params
    self.params.require(:staticpage).permit(:name, :email, :content)
  end
end
```

# お問合せテンプレートの作成
お問合せフォームのテンプレートを作成する。
モデルの設定でバリデーションをかけているので、エラーを表示する部分も追加している。
```html:contact.html.erb
<h1>Contact</h1>
<p>
  コンタクトページです。<br>
  お問合せの際は下記より、お願いします。
</p>
<%= form_with(model: @contact, local: true, url: confirm_path) do |f| %>
  <%= render 'shared/error_messages', object: f.object %>

  <%= f.label :name, 'お名前' %>
  <%= f.text_field :name, class: 'form-control', autofocus: true %>

  <%= f.label :email, 'メールアドレス' %>
  <%= f.email_field :email, class: 'form-control' %>
  
  <%= f.label :content, 'お問合せ内容' %>
  <%= f.text_area :content, class: 'form-control long-content' %>

  <%= f.submit '入力内容を確認する', class: "btn btn-primary" %>
<% end %>
```
エラーメッセージのパーシャルも確認する。
```html: app/views/shared/_error_messages.html.erb
<% if object.errors.any? %>
  <div id="error_explanation">
    <div class="alert alert-danger">
      The form contains <%= pluralize(object.errors.count, "error") %>.
    </div>
    <ul>
    <% object.errors.full_messages.each do |msg| %>
      <li><%= msg %></li>
    <% end %>
    </ul>
  </div>
<% end %>
```

# 確認画面テンプレートを作成
入力した内容を確認し、下記を選択することができるテンプレートを作成する。
・OKなら送信
・修正したいなら情報を保持したまま戻る

```html:confirm.html.erb
<h1>確認画面</h1>
<%# 入力した内容を表示する。OKなら送信する。 %>
<%= form_with(model: @contact, local: true) do |f| %>
    <%= f.label :name, 'お名前' %>
    <div class="confirm"><%= params[:staticpage][:name] %></div>
    <%= f.hidden_field :name %>
    <%= f.label :email, 'メールアドレス' %>
    <div class="confirm"><%= params[:staticpage][:email] %></div>
    <%= f.hidden_field :email %>
    <%= f.label :content, 'お問合せ内容' %>
    <div class="confirm"><%= params[:staticpage][:content] %></div>
    <%= f.hidden_field :content %>
  <div><%= f.submit '入力内容を送信する', class: "btn btn-primary" %></div>
<% end %>

<%# 入力内容を修正したいなら、back_pathに送信すると、情報保持してお問合せフォームに戻る。 %>
<%= form_with(model: @contact, local: true, url: back_path) do |f| %>
  <%= f.hidden_field :name %>
  <%= f.hidden_field :email %>
  <%= f.hidden_field :content %>
  <div><%= f.submit '入力画面に戻る', class: "btn btn-primary" %></div>
<% end %>
```
上の送信をすると、デフォルトでcreateアクションが実行される（メールが送信される。）。
下の送信をすると、url: back_pathによりbackアクションが実行される。（お問い合わせフォームをレンダリングする。）。下図再掲。
![スクリーンショット 2022-08-10 0.18.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2684787/f4864a35-139e-1b1c-837d-1d6cfbab1111.png)

# mailerの設定
まだ、mailerの設定をしていないため、deliver_nowが発火せず、メールが送信されない。設定していく。
```app/mailers/user_mailer.rb
class UserMailer < ApplicationMailer
  def contact(contact)
    @contact = contact
    mail from: contact.email, to: ENV['GMAIL_USER'], subject: "【糖質村】お客様からのお問合せ"
    # => デフォルトでapp/views/user_mailer/contact.html.erb もしくは、app/views/user_mailer/contact.text.erbのテンプレートを探しにいく。
  end
end
```
引数contactに、お問合せフォームで入力された内容を代入し、保持する。
このデータを次のメールテンプレートで使用する。

# メールテンプレートの作成
メールテンプレートを作成し、お問合せを受けた内容をメール本文に記載されるよう設定する。
```html:app/views/user_mailer/contact.html.erb
<h1><%= @contact.name %> 様 からお問い合わせがありました。</h1>
<p>【Mail】: <%= @contact.email %></p>
<p>【お問い合わせ内容】</p>
<span style="white-space: pre-wrap;"><%= @contact.content %></span>
```
```html:app/views/user_mailer/contact.text.erb
<%= @contact.name %> 様 からお問い合わせがありました。
【Mail】: <%= @contact.email %>
【お問い合わせ内容】
<%= @contact.content %>
```

# 環境変数の設定
最後に環境変数の設定をしていく。これをしないと、その環境でmailerを使えない。

https://qiita.com/vaza__ta/items/9693feaa776afa07c865

以前もActionMailerを使っていたため、環境変数は特に今回いじっていないが一応記載する。
```development.rb
  config.action_mailer.asset_host = 'http://localhost:3000'
  config.action_mailer.raise_delivery_errors = true
  host = 'localhost:3000'
  config.action_mailer.default_url_options = { host: host, protocol: 'http' }
  config.action_mailer.delivery_method = :smtp
  ActionMailer::Base.smtp_settings = {
    :port           => 587,
    :address        => 'smtp.gmail.com',
    :user_name      => ENV['GMAIL_USER'],
    :password       => ENV['GMAIL_PASS'], # Googleが発行する、16桁のアプリケーションパスワード
    :domain         => 'gmail.com',
    :authentication => :plain, # 'plain'と書く記事もあり
    :enable_starttls_auto => true
  }
```
```~/.zshrc
# 環境変数
export GMAIL_USER='使用するemail'
export GMAIL_PASS='上記メールのpassword' # アプリパスワード
```

# おわりに
これで、全ての設定を完了し、お問合せ内容がメールで確認できるようになった。