実装の目標
お問い合わせ機能をつくり、お問い合わせを送信したタイミングで管理者とお問い合わせしたユーザーの2名に確認メールを送信。(お問い合わせ内容はDBに保存されます)
この記事を読んでもらえると上記が実装できます!
この記事の対象となる人
- お問い合わせ機能を実装したい人
- 送信時に確認メールを送りたい人
- 確認画面を挟んでから送信したい人
開発環境
ruby 2.6.3
Rails 5.2.6
前提
Gmailを使ってメールを送信しまので、Gmailの2段階認証とアプリパスワードの設定を行っておきましょう。
アプリパスワードはあとでまた必要になってくるのでコピペしておきましょう!(Gmailの設定方法については、記事内部にもリンク入れてるのであとで設定でもOK)
gem 'dotenv-rails'
で環境変数も使います。
モデル名、変数名等は適宜、ご自身の開発環境に変換してお考えください。
モデル作成
今回はお問い合わせ内容をDBに保存するので、contactモデルを作っていきます。
$rails g model Contact
作られたマイグレーションファイルにカラムを追加していきます。
class CreateContacts < ActiveRecord::Migration[5.2]
def change
create_table :contacts do |t|
t.string :name #名前カラム追加
t.string :email #メールアドレスカラム追加
t.string :content #お問い合わせ内容カラム追加
t.timestamps
end
end
end
追加できたらモデルを作成します。
$rails db:migrate
contactモデルにバリデーションをかけていきます。
今回は全てに空のデータはだめ、名前は20文字以内、お問い合わせ内容は10文字以上でバリデーションをかけます。
class Contact < ApplicationRecord
validates :name, presence: true, length: { maximum: 20 }
validates :email, presence: true
validates :content, presence: true, length: { minimum: 10 }
end
コントローラー作成
次にコントローラーをつくっていきます。
今回はビューは新規登録画面、確認画面、完了画面が必要なので、コントローラー作成と同時にビューも作っていきます。
$rails g controller contacts new confirm complete
これで、コントローラーとビューが作成されました。
コントローラーにcreateアクションを追加しておきます。
コントローラーの記述は順番にいきたいので、後述します。
class ContactsController < ApplicationController
def new
end
def confirm
end
# 追加
def create
end
def complete
end
end
ルーティング設定
コントローラーを作ったときにgetルーティングが作成されますが、いらないので削除してルーティングを設定します。
newとcreateはresourcesを使って、confirmとcompleteはcollectionを使います。
confirmのHTTPメソッドがpostなのは、new画面のお問い合わせフォームからpostで入力データを渡されるから。
Rails.application.routes.draw do
get 'contacts/new' #削除
get 'contacts/confirm' #削除
get 'contacts/complete' #削除
:
# 追加
resources :contacts, only: [:new, :create] do
collection do
post :confirm
get :complete
end
end
end
ビュー作成
ここまで来たらビューを作成していきます。
デザインは適宜変更してください。(Bootstrap使ってます)
まずはnew画面から
今回は、DBを保存する前に確認画面をはさみたいので、form_withのデータの送信先をcontactsコントローラーのconfirmアクションを指定
します。
<div class="container">
<h2 class="my-3 ml-3">
お問い合わせフォーム
</h2>
<div class="row">
<div class="col-sm-10 mx-auto">
<!--confirmアクションに送る-->
<%= form_with model: @contact, local: true, url: {action: :confirm} do |f| %>
<!--エラーメッセージ部分テンプレート化しています-->
<%= render 'layouts/error_messages', model: f.object %>
<div class="form-group">
<%= f.label :name, 'お名前' %><br>
<%= f.text_field :name, autofocus: true, placeholder:'テスト ほげ太郎', class:'form-control' %>
</div>
<div class="form-group">
<%= f.label :email, 'メールアドレス' %><br>
<%= f.text_field :email, placeholder:'test@hoge.com', class:'form-control' %>
</div>
<div class="form-group">
<%= f.label :content, 'お問い合わせ内容' %><br>
<%= f.text_area :content, placeholder:'お問い合わせ内容は10文字以上でお願いします', class:'form-control' %>
</div>
<div class="d-flex justify-content-center mb-5">
<%= f.submit '確認画面へ進む', class:'btn btn-primary' %>
</div>
<% end %>
</div>
</div>
</div>
次に確認画面
ここでのポイントは3つ
- form_withの送信先をcreateアクションを指定
- form_withをmethod: :postで送信
- f.hidden_fieldでデータを送信
f.hidden_fieldはデータの受け渡しに使い、通常のフォームと違ってビューに表示はされません。
確認画面からcreateアクションにnew画面で入力したデータを送りたいので、f.hidden_fieldのvalueにデータを入れてその値をcreateアクションに送ります。
ぼくもここの仕組みの理解にはかなり時間がかかりましたが、確実に理解しておきましょう。
<div class="container">
<h2 class="my-3 ml-3">
お問い合わせ内容確認
</h2>
<div class="row">
<div class="col-sm-10 mx-auto">
<%= form_with model: @contact, local: true, url: {action: 'create'}, method: :post do |f| %>
<div class="form-group border-bottom">
<%= f.label :name, 'お名前' %><br>
<!--ビューに表示させている部分-->
<%= @contact.name %>
<!--データの受け渡しに必要-->
<%= f.hidden_field :name, :value => @contact.name %>
</div>
<div class="form-group border-bottom">
<%= f.label :email, 'メールアドレス' %><br>
<!--ビューに表示させている部分-->
<%= @contact.email %>
<!--データの受け渡しに必要-->
<%= f.hidden_field :email, :value => @contact.email %>
</div>
<div class="form-group border-bottom">
<%= f.label :content, 'お問い合わせ内容' %><br>
<!--ビューに表示させている部分-->
<%= @contact.content %>
<!--データの受け渡しに必要-->
<%= f.hidden_field :content, :value => @contact.content %>
</div>
<div class="d-flex justify-content-center mb-5">
<%= f.submit '送信する', class:'btn btn-primary' %>
</div>
<% end %>
</div>
</div>
</div>
最後に、完了画面です。
<div class="container">
<h2 class="my-3 ml-3 heading">
お問い合わせ完了
</h2>
<div class="row">
<div class="col-sm-10 mx-auto text-center mt-3">
<h3 class="mb-5">お問い合わせありがとうございました</h3>
<p>
確認メールを送信させて頂きましたので、<br>
ご確認ください。
</p>
<div class="d-flex justify-content-center mb-5">
<%= link_to 'Topへ戻る', root_path, class:'btn btn-info mb-5 mt-3' %>
</div>
</div>
</div>
</div>
コントローラーの記述
ビューまで出来たので、まずはお問い合わせ機能の投稿する流れの処理をコントローラーに記述していきます。
お問い合わせ機能はログインしてなくても使える機能にしたいので、before_actionで許可しておきます。
new画面で入力したフォームの値はContact.new(contact_params)
で受け取ることができます。
class ContactsController < ApplicationController
before_action :authenticate_user!, except: [:new, :confirm, :complete, :create]
def new
@contact = Contact.new
end
def confirm
@contact = Contact.new(contact_params)
end
def create
@contact = Contact.new(contact_params)
if @contact.save
redirect_to complete_contacts_path, notice: 'お問い合わせ内容を送信しました'
else
render :new
end
end
def complete
end
private
def contact_params
params.require(:contact).permit(:name, :email, :content)
end
end
これで、お問い合わせをDBに保存するまでの処理が出来ました。
では残りのAction Mailerを使ってメール送信される機能を実装していきましょう!
メール機能実装
まずはRailsに標準搭載されているAction Mailerを使ってmailerを作っていきます。
このmailerでメール送信の設定等を行っていきます。
コマンドを実行
$rails g mailer contact
mailers直下にcontact_mailer.rbがあるので、処理を記述していきます。
ここでは、mailの送信元、送信先、件名、bccを設定していきます。(もっと色々な設定ができるので調べてみてください)
ENV['SEND_MAIL']の部分は環境変数を使っています、わからない方も後で説明しますので安心してください。
class ContactMailer < ApplicationMailer
def contact_mail(contact)
@contact = contact
mail(
from: ENV['SEND_MAIL'], #送信元アドレス
to: contact.email, #送信先アドレス
subject: 'お問い合わせを承りました', #メールの件名
bcc: ENV['SEND_MAIL'] #BCC送信先アドレス
)
end
end
SMTPサーバー設定
Gmailの送信設定をします。
SMTPサーバーの設定をしていきます。(ここで使ってる環境変数も後で説明します)
:
config.action_mailer.raise_delivery_errors = true #34行目 falseをtrueに変更
:
# お問い合わせメールの送信設定
config.action_mailer.delivery_method = :smtp
config.action_mailer.smtp_settings = {
address: 'smtp.gmail.com',
port: 587,
domain: 'gmail.com',
user_name: ENV['SEND_MAIL'],
password: ENV['SEND_MAIL_PASSWORD'],
authentication: 'plain',
enable_starttls_auto: true
}
メール本文用意
実際に送られるメールを作っていきます。
htmlファイルのみ、textファイルのみしか受け取れない場合を想定して、htmlファイル、textファイルの2つ用意します。
views/contact_mailer直下にcontact_mail.html.erb
とcontact_mail.text.erb
を作成
<h5><%= @contact.name %>様 からお問い合わせを承りました</h5>
<h2>【お問い合わせ内容】</h2>
<p>
<%= @contact.content %><br>
</p>
<p>
お問い合わせありがとうございます。<br>
</p>
<p>
【管理者】
</p>
<%= @contact.name %>様 からお問い合わせを承りました
=====================================================
【お問い合わせ内容】
<%= @contact.content %>
お問い合わせありがとうございます。
【管理者】
コントローラーに追加
contactsコントローラーのcreateされたタイミングでメールを送りたいので、コントローラーにメール送信処理を追加します。
:
def create
@contact = Contact.new(contact_params)
if @contact.save
ContactMailer.contact_mail(@contact).deliver #メール送信処理追加
redirect_to complete_contacts_path, notice: 'お問い合わせ内容を送信しました'
else
render :new
end
end
:
環境変数を使う
Gmailのメール設定まだの方はしておいてください。
アプリパスワードが必要になってきます。
これでほぼ完成していますが、環境変数の設定がまだなので設定していきます。
なぜ環境変数を使うのかはセキュリティ上の問題があるからです。
今までの箇所でENVを使ってるところが環境変数なのですが、ここに直接メールアドレスやパスワードなどを入力しても動作上は全く問題ないです。
しかし、GitHubなどにあげたら全世界にメールアドレスやパスワードを公開してしまいます。
そこで、環境変数を使ってメールアドレスやパスワードを分からない状態にする必要があります。
ここまで理解した上で環境変数を使っていきましょう!
まずはgemを用意して、bundle installします。
gem 'dotenv-rails'
$bundle install
次にアプリケーションファイル直下
に.envファイルを作成します。
階層は.gitignoreやGemfileと同じ階層に作成してください。
.envファイルに環境変数を定義します。
ここで定義した環境変数はENV['']で呼び出すことが出来ます。
SEND_MAIL = '<gmailのメールアドレス>'
SEND_MAIL_PASSWORD = '<Googleで設定した、アプリパスワード>'
ただ、このままだと.envファイルもGitHubにアップロードされてしまうので、.gitignoreファイルに.envを追加してアップロードされないようにします。
必ず追記するようにしてください。
.gitignoreファイルに追加しないと結局全世界に公開されるのでなんの意味もないです。
:
.env
これでメールが送信されるので試してみてください!
最後に
今回はお問い合わせ送信時に確認用のメールを送信する機能を実装しました。
smtpの理解ぐらいでそこまで難しくなかったと思います。
ポートフォリオサイトにてこの機能を実装して、デプロイ後の動作確認で動かなくなったときは、なんで?と思いましたが、smtpサーバーの設定をconfig/environments/development.rb
でしか記述してなかったからという凡ミスでした。
config/environments/production.rb
に同じ記述をするだけで解決しましたが、開発環境と本番環境の認識等、まだまだだなと痛感しました。。
みなさんもデプロイの際はお気をつけくださいww