Railsでお問合せ機能実装。

Ruby(Ruby on Rails)使って、お問い合わせ機能を作った際に多少詰まったりしたのでメモ代わりとして備忘録残しておきます。
またこれから機能実装する人、プログラミング初心者に向けても書いてるので是非参考になればと。

### 参考にした資料
以下参考にした資料等です。今回機能実装に向けて何個か資料を参考にして完成させました。参照元の資料にはほんと感謝です。

[Action mailer参考資料１](https://www.imd-net.com/column/1731/)→ほぼこの資料がベースです。ただある程度Rails触ったことある人向けに書かれてる印象で、ファイル作成のコマンド実行など一切ないのと、paramsの受取エラーやSMTPのエラーなど、記事通りに行かない点がありました。でもこの記事のおかげで完成したのでとても感謝してます！

[Action mailer参考資料２](https://www.sejuku.net/blog/48739)→有名なスクールさんですね。最初この記事を参考にしてたのですが、メーラーでの確認のところが自分的に微妙だったのでSMTPの設定のところだけ最終的には参考にしました。

[環境変数の参考資料](https://qiita.com/yuichir43705457/items/7cfcae6546876086b849)→機能とは実際には関係ないのですが、セキュリティ面と今後も使える技術なので導入しました。

## プロジェクトの作成

プロジェクトを作成します。今回プロジェクト名は問合せ機能のテストアプリなのでinquiryTestAppとします。

```ruby:console
rails new inquiryTestApp
```

```ruby:出力結果
create  
create  README.md
create  Rakefile
・
・
・
＜中略＞
・
・
・
└─ yargs@12.0.5
✨  Done in 5.58s.
Webpacker successfully installed 🎉 🍰
```

「successfully」が出ればOK。

## 必要なファイルの生成

次に、作業Dirに移動しコントローラなどを作成します。

```ruby:console
cd inquiryTestApp
rails g controller inquiry index confirm thanks
```

「rails g controller」の後ろ３つの引数について。
Viewを作成してます。(任意のファイル名を指定できます。)以下各Viewの説明。

・index→問合せ画面（初期表示画面）
・confirm→問合せ確認画面
・thanks→問合せ完了通知画面

```ruby:出力結果
Running via Spring preloader in process 1987
      create  app/controllers/inquiry_controller.rb
       route  get 'inquiry/index'
get 'inquiry/confirm'
get 'inquiry/thanks'
      invoke  erb
      create    app/views/inquiry
      create    app/views/inquiry/index.html.erb
      create    app/views/inquiry/confirm.html.erb
      create    app/views/inquiry/thanks.html.erb
      invoke  test_unit
      create    test/controllers/inquiry_controller_test.rb
      invoke  helper
      create    app/helpers/inquiry_helper.rb
      invoke    test_unit
      invoke  assets
      invoke    scss
      create      app/assets/stylesheets/inquiry.scss
```

中段あたり、View(html.erb)が３つcreateされてることが分かる。

次にmailer作成。今回初めて知ったのですが、Active Mailerと言う機能が標準搭載してあるらしくcontrollerやmodel同様railsコマンドでファイル作成することができます。手動で作成してもいいのですがせっかくなので今回はコマンド使っていきます。

```ruby:console
rails g mailer inquiry
```
以下出力結果。いろいろと作成されているが、今回は1行目の「inquiry_mailer.rb」のみをいじっていく。

```ruby:出力結果
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
```
次にmodelの作成。
通常はコマンド(rails g model)を使うのですが、今回はDBを使わないので（model/inquiry.rb）を手動にて作成（Linuxコマンド使います！）。railsコマンドを使うとmigrateファイルとかを作成してしまい消すのが面倒・・・

```console:console
touch app/models/inquiry.rb
```

コマンド実行後、VSCodeのフォルダーツリーが以下のようになってればOK。

<img width="333" alt="f72dddef13636ef752d616b7dd5f3ad2.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/26010e7d-ebd5-c587-4644-e61d9079d6a7.png">

## コードを書く

ここまで揃えたらいよいよコードを書いていく。
まずはmodel今回はDBを使わないので「ActiveModel」（以下2行目）を使用してます。

```ruby:model/inquiry.rb
class Inquiry
  include ActiveModel::Model
 
  attr_accessor :name, :email, :message
 
  validates :name, :presence => {:message => '名前を入力してください'}
  validates :email, :presence => {:message => 'メールアドレスを入力してください'}
end
```

次にcontroller。

```ruby:controllers/inquiry_controller.rb
class InquiryController < ApplicationController
  def index
    # 入力画面を表示
    @inquiry = Inquiry.new
    render :action => 'index'
  end
 
  def confirm
    # 入力値のチェック
    @inquiry = Inquiry.new(params[:inquiry].permit(:name, :email, :message))
    if @inquiry.valid?
      # OK。確認画面を表示
      render :action => 'confirm'
    else
      # NG。入力画面を再表示
      render :action => 'index'
    end
  end
 
  def thanks
    # メール送信
    @inquiry = Inquiry.new(params[:inquiry].permit(:name, :email, :message))    
    InquiryMailer.received_email(@inquiry).deliver
 
    # 完了画面を表示
    render :action => 'thanks'
  end
end
```
controllerで記載したメソッドに沿ってViewを作成。

```ruby:views/inquiry/index.html.erb
<%= form_for @inquiry, :url => inquiry_confirm_path do |f| %>
  <div class="page-header">
    <h1>お問い合わせ</h1>
  </div>
 
  <% if @inquiry.errors.any? %>
    <div class="alert alert-danger" role="alert">
      <strong>入力内容にエラーがあります</strong>
      <ul>
        <% @inquiry.errors.each do |attr, msg| %>
          <li><%= msg %></li>
        <% end %>
      </ul>
    </div>
  <% end %>
 
  <table class="table">
    <tr>
      <th>名前<span class="text-danger">（必須）</span></th>
      <td><%= f.text_field :name %></td>
    </tr>
    <tr>
      <th>メールアドレス<span class="text-danger">（必須）</span></th>
      <td><%= f.text_field :email %></td>
    </tr>
    <tr>
      <th>お問い合わせ内容</th>
      <td><%= f.text_area :message %></td>
    </tr>
  </table>
  <%= f.submit '確認', class: 'btn btn-primary' %>
<% end %>
```

```ruby:views/inquiry/confirm.html.erb
<div class="page-header">
  <h1>お問い合わせ</h1>
</div>
 
<%= form_for @inquiry, :url => inquiry_thanks_path do |f| %>
  <table class="table">
    <tr>
      <th>名前</th>
      <td>
        <%= f.hidden_field :name %>
        <%= @inquiry.name %>
      </td>
    </tr>
    <tr>
      <th>メールアドレス</th>
      <td>
        <%= f.hidden_field :email %>
        <%= @inquiry.email %>
      </td>
    </tr>
    <tr>
      <th>お問い合わせ内容</th>
      <td>
        <%= f.hidden_field :message %>
        <%= simple_format(@inquiry.message) %>
      </td>
    </tr>
  </table>
  <%= f.submit '送信', :class => 'btn btn-primary' %>
<% end %>
```

```ruby:views/inquiry/thanks.html.erb
<div class="page-header">
  <h1>お問い合わせ</h1>
</div>
<p>
  お問い合わせいただきありがとうございました。
</p>
```

作成したViewとControllerを結び付けるため、ルーティンを設定。

```ruby:config/routes.rb
Rails.application.routes.draw do
  root  'inquiry#index'
  get   'inquiry'         => 'inquiry#index'     # 入力画面
  post  'inquiry/confirm' => 'inquiry#confirm'   # 確認画面
  post  'inquiry/thanks'  => 'inquiry#thanks'    # 送信完了画面
end

```
controllerのthanksメソッドが呼ばれる、mailer class。

```ruby:mailers/inquiry_mailer.rb
class InquiryMailer < ApplicationMailer
  default from: "example@example.com"   # 送信元アドレス
 
  def received_email(inquiry)
    @inquiry = inquiry
    mail(:to => inquiry.email, :subject => 'お問い合わせを承りました')
  end
end
```

gmail送信用の設定をする。SMTPサーバ（メールの送信用サーバ）を使える用にしてます。詳しくは[こちらのサイト](https://www.kagoya.jp/howto/rentalserver/smtpserver/)に説明があります。
実は以下の記述だけだとセキュリティの関係でエラーが出て送信ができない。そのためGoogleアカウント側で認証設定が必須で、その対応は後ほど紹介するのでご安心を。

```ruby:config/environments/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:            '<gmailのメールアドレス>',
  password:             '<gmailのパスワード>',
  authentication:       'plain',
  enable_starttls_auto:  true
}
```

最後に、メールのテンプレートを作成。ここ実は良くわかってないのだが、恐らくmailersで作成したメソッド名と紐付いててメール送信時にこのテンプレートを読み込んでるのだと思う。曖昧な表現でごめんなさい。これが会社だったら怒られるねｗ

```ruby:views/inquiry_mailer/received_email.text.erb
Webサイトからお問い合わせがありました。
 
--------------------------
Name: <%= @inquiry.name %>
Email: <%= @inquiry.email %>
Message:
<%= @inquiry.message %>
--------------------------
```

現状このままだと、メール送信でエラーが出て送れないので、Googleの二段階認証の設定をします。
ここはちょっと長くなるので、[こちらなど](https://enjoypclife.net/2018/02/04/google-account-gmail-2-step-verification/)外部の資料を参照して下さい。

上記が出来たなら今度はアプリからのアクセスを可能にするため、アプリパスワードを設定します。手順は[こちらなど](https://www.howtonote.jp/google-account/2step-verify/index6.html)を参照。
**<font color="red">※設定したアプリパスワードは忘れずメモっておくように！</font>**

ここまで出来たら、development.rbを編集していきます。

```ruby:config/environments/development.rb
【変更前】
password:             '<gmailのパスワード>'
↓
【変更後】
password:             '<Googleで設定した、アプリパスワード>'
```

ここまで出来ると、問合せ機能が出来ると思います。
動作確認していきましょう。serverを立ち上げ、localhost:3000にアクセスしましょう。アプリを開けば何となく使い方が分かるかと思います。

## 環境変数を使う

動作確認でメールを受信できる事を確認出来たら、これで機能実装は完了なのですが、１つ問題があります。Gmailアドレスとパスワードを直書きしてることです。このコードをGithubなどにあげたら全世界にアドレスとパスを公開してしまうことになるのでそれはセキュリティ上よろしくないのでこの問題を改善します。

方法は何個かあると思いますが、今回は.envという環境変数用ファイルを使う方法を取っていきます。

gemを用意する。

```ruby:Gemfile
gem 'dotenv-rails'
```

インストール。

```ruby:console
bundle install
```

.envファイルを作成します。（プロジェクトファイル直下）

```console:console
touch .env
```

VSCodeのフォルダーツリーが以下のようになってればOK。
<img width="335" alt="5d6e90cae2891ed4fc75b58ac12f7782.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/420031/cf6b30e5-2869-5e19-c1ca-a05184e32572.png">

環境変数を作成していきます。

```ruby:.env
SEND_MAIL='＜gmailのメールアドレス＞'
SEND_MAIL_PASSWORD='＜Googleで設定した、アプリパスワード＞'
```

これで環境変数が使えるようになったので、問題のdevelopment.rbを編集していきます。
ここで言う環境変数とは上記コードの代入式の左側の変数部分の事です。
ENV['＜変数＞']とする事で環境変数を使うことが出来きます。

```ruby:config/environments/development.rb
【変更前】
user_name:            '<gmailのメールアドレス>',
password:             '<Googleで設定した、アプリパスワード>',
↓
【変更後】
user_name:            ENV['SEND_MAIL'],
password:             ENV['SEND_MAIL_PASSWORD'],
```

最後にアップロードの制限をかけます。.gitignoreに以下を追記しましょう。

```ruby:.gitignore
.env
```

これで完成しました。再度serverを立ち上げなおしてアプリの動作確認をしましょう。先程と同等の動きになるかと思います。

## 最後に

お疲れ様でした。少し長い記事になってしまいましたが、最後まで読んでくれた方本当にありがとうございました。きっちり問い合わせ機能について書いてる記事が無かったので誰かの助けになれば幸いです。
またこの実装自体まだまだ改善出来るところは山ほどあるので時間がある時にでも更新していこうかと思います。