【Rails】お問い合わせフォーム(確認画面付き)の実装手順【完全版】

2019年10月10日 21:32

    はじめに

    お問い合わせフォームの実装手順をいつも忘れてしまうので、完全な実装手順をまとめます。

    メーラー作成

    以下のコマンドを実行し、メーラーを作成します。
    $ rails g mailer ContactMailer
    作成されたメーラー「app/mailers/contact_mailer.rb」を編集します。
    class ContactMailer < ApplicationMailer
      default from: 'noreply@example.com'
      default to: 'admin@example.com'
      layout 'mailer'
    
      def send_mail(contact)
        @contact = contact
        mail(from: contact.email, to: ENV['MAIL_ADDRESS'], subject: 'Webサイトより問い合わせが届きました') do |format|
          format.text
        end
      end
    end
    メール本文になるテンプレートファイル「app/views/contact_mailer/send_mail.text.erb」を編集します。
    <%= @contact.content %>
    
    <%= @contact.name %> (<%= @contact.email %>)

    コントローラー作成

    以下のコマンドを実行し、コントローラーを作成します。
    $ rails g controller Contacts
    作成されたコントローラー「app/controllers/contacts_controller.rb」を編集します。
    class ContactsController < ApplicationController
      def index
          @contact = Contact.new
        end
       
        def confirm
          @contact = Contact.new(contact_params)
          if @contact.valid?
            render :action => 'confirm'
          else
            render :action => 'index'
          end
        end
    
        def done
          @contact = Contact.new(contact_params)
          if params[:back]
            render :action => 'index'
          else
            ContactMailer.send_mail(@contact).deliver_now
            render :action => 'done'
          end
        end
    
        private
          def contact_params
            params.require(:contact).permit(:name, :email, :content)
          end
    end

    モデル作成

    メールを送信するだけならDBは必要ないので、ActiveModelを使います。
    「app/models/contact.rb」を手動作成(rails generateは使わない)し、編集します。
    class Contact include ActiveModel::Model
        attr_accessor :name, :email, :content
       
        validates :name, presence: true, length: { maximum: 20 }
        VALID_EMAIL_REGEX = /\A[\w+\-.]+@[a-z\d\-.]+\.[a-z]+\z/i
        validates :email, presence: true, length: { maximum: 30 },
                          format: { with: VALID_EMAIL_REGEX }
        validates :content, presence: true, length: { maximum: 500 }
    end

    ビュー作成

    以下の3ファイルを作成します。

    app/views/contacts/index.html.erb
    <% provide :title, 'お問い合わせ' %>
    <div class="container mt-4">
      <div class="row">
        <div class="col-md-12 col-lg-6 offset-lg-3">
          <h2><%= icon('fas', 'envelope') %> お問い合わせ</h2>
          <nav aria-label="パンくずリスト" class="small">
            <ol class="breadcrumb">
              <li class="breadcrumb-item"><%= link_to 'トップページ', root_path %></li>
              <li class="breadcrumb-item active" aria-current="page">お問い合わせ</li>
            </ol>
          </nav>
          <hr />
          
          <%= form_with model: @contact, local: true, url: contact_confirm_path do |form| %>
            <% if @contact.errors.any? %>
              <div class="alert alert-danger" role="alert">
                <h5><strong>入力内容にエラーがあります。</strong></h5>
                <ul>
                  <% @contact.errors.full_messages.each do |message| %>
                    <li><%= message %></li>
                  <% end %>
                </ul>
              </div>
            <% end %>
    
            <div class="form-group">
              <%= form.label :name, '名前' %>
              <span class="badge badge-info rounded-0">必須</span>
              <%= form.text_field :name, id: 'name', class: 'form-control', :placeholder => '名前' %>
            </div>
    
            <div class="form-group">
              <%= form.label :email, 'メールアドレス' %>
              <span class="badge badge-info rounded-0">必須</span>
              <small class="text-muted">例:user@example.com</small>
              <%= form.text_field :email, id: 'email', class: 'form-control', :placeholder => 'メールアドレス' %>
            </div>
    
            <div class="form-group">
              <%= form.label :content, 'お問い合わせ内容' %>
              <span class="badge badge-info rounded-0">必須</span>
              <small class="text-muted">パスワードなどの機密情報を含めないでください。</small>
              <%= form.text_area :content, id: 'content', class: 'form-control', :placeholder => 'お問い合わせ内容', :rows => '5' %>
            </div>
    
            <div class="float-right">
              <%= form.submit "確認", class: "btn btn-dark" %>
            </div>
          <% end %>
    
        </div>
      </div>
    </div>

    app/views/confirm.html.erb
    <% provide :title, 'お問い合わせ' %>
    <div class="container mt-4">
      <div class="row">
        <div class="col-md-12 col-lg-6 offset-lg-3">
          <h2><%= icon('fas', 'envelope') %> お問い合わせ</h2>
          <nav aria-label="パンくずリスト" class="small">
            <ol class="breadcrumb">
              <li class="breadcrumb-item"><%= link_to 'トップページ', root_path %></li>
              <li class="breadcrumb-item active" aria-current="page">お問い合わせ</li>
            </ol>
          </nav>
          <hr />
    
          <%= form_with model: @contact, local: true, url: contact_done_path do |form| %>
    
            <div class="form-group">
              <%= form.label :name, '名前' %>
              <%= form.text_field :name, value: @contact.name, id: 'name', class: 'form-control-plaintext', :placeholder => '名前' %>
            </div>
    
            <div class="form-group">
              <%= form.label :email, 'メールアドレス' %>
              <%= form.text_field :email, value: @contact.email, id: 'email', class: 'form-control-plaintext', :placeholder => 'メールアドレス' %>
            </div>
    
            <div class="form-group">
              <%= form.label :content, 'お問い合わせ内容' %>
              <%= form.text_area :content, value: @contact.content, id: 'content', class: 'form-control-plaintext', :placeholder => 'お問い合わせ内容', :rows => '5' %>
            </div>
    
            <p>この内容で送信します。よろしいですか?</p>
    
            <div class="float-right">
              <%= form.submit "戻る", name: 'back', class: "btn btn-dark" %>
              <%= form.submit "送信", class: "btn btn-dark" %>
            </div>
          <% end %>
    
        </div>
      </div>
    </div>

    app/views/done.html.erb
    <% provide :title, 'お問い合わせ' %>
    <div class="container mt-4">
      <div class="row">
        <div class="col-md-12 col-lg-6 offset-lg-3">
          <h2><%= icon('fas', 'envelope') %> お問い合わせ</h2>
          <nav aria-label="パンくずリスト" class="small">
            <ol class="breadcrumb">
              <li class="breadcrumb-item"><%= link_to 'トップページ', root_path %></li>
              <li class="breadcrumb-item active" aria-current="page">お問い合わせ</li>
            </ol>
          </nav>
          <hr />
    
          <p>ありがとうございます。お問い合わせ内容を送信しました。</p>
    
        </div>
      </div>
    </div>

    メール送信設定

    本番環境と開発環境で手順が異なります。

    開発環境
    「config/environments/development.rb」に以下を追記します。
      config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
      config.action_mailer.delivery_method = :smtp
      config.action_mailer.smtp_settings = { address: 'localhost', port: 1025 }
      config.action_mailer.raise_delivery_errors = true

    本番環境
    「config/environments/development.rb」に以下を追記します。
      config.action_mailer.default_url_options = {  host: 'localhost', port: 3000 }
      config.action_mailer.delivery_method = :smtp
      config.action_mailer.raise_delivery_errors = true
      config.action_mailer.smtp_settings = {
        :address => "smtp.gmail.com",
        :port => 587,
        :user_name => ENV['MAIL_ADDRESS'],
        :password => ENV['MAIL_PASSWORD'],
        :authentication => :plain,
        :enable_starttls_auto => true
      }

    環境変数の設定

    送信先メールアドレスやパスワードをソースに直書きしてしまうとセキュリティ的に問題があるので、通常は環境変数に設定しておきます。
    Gemfileに以下を追加し、bundle installを実行します。
    gem 'dotenv-rails'
    dotenv-railsを導入することで、.envに記載されている環境変数をENV['variable name']の形式で参照できるようになります。
    .envを作成し以下を追加します。
    「MAIL_ADDRESS」には送信先のメールアドレス(今回はGmail)、「MAIL_PASSWORD」にはGoogleのアプリパスワードを設定します。
    MAIL_ADDRESS=Your mail address
    MAIL_PASSWORD=Your mail password
    .envをGithubなどのリモートサーバーにアップロードしてしまうと、やはりセキュリティ的に問題があるので、.envをコミット対象から除外します。
    .gitignoreに以下を追記します。
    /.env
    .envをコミット対象から除外してしまうと、将来クローンしたときにどういう環境変数を設定したらいいかわからなくなってしまうので、環境変数名だけ記載したファイルを作成しておきます。
    .env.sampleを作成し以下を追加します。
    MAIL_ADDRESS=
    MAIL_PASSWORD=

    メール送信確認

    ここまで行えばメール送信ができるようになっているはずです。最後にメール送信確認を行いましょう。

    開発環境
    開発環境では実際に設定したGmail宛に送信するのではなく、MailCatcherというGemが構築してくれるメールサーバー宛に送信します。
    Gemfileに以下を追加し、bundle installを実行します。
    gem 'mailcatcher'
    ターミナルで以下のコマンドを実行します。
    $ mailcatcher
    ブラウザで「http://localhost:1080/」にアクセスすると、MailCatcherのメールボックスが表示されます。
    この状態でお問い合わせフォームからメール送信するとMailCatcherのメールボックスにメールが届きます。

    本番環境
    デプロイ先がHerokuの場合、Herokuに環境変数を設定する必要があります。
    ターミナルで以下を実行します。
    $ heroku config:set MAIL_ADDRESS=Your mail address
    $ heroku config:set MAIL_PASSWORD=Your mail password
    本番環境では設定したGmail宛にメールが送信されるので、Gmailのメールボックスにメールが届くが確認します。

    参考

    関連記事

    関連記事はありません。