Dockerを使ったRuby on Railsで問い合わせフォームの作成

#問い合わせ機能の実装
自分向け個人的な備忘録。
開発環境はDockerを使用。
view画面ではhamlを使用。
行う順序としては

1. routesの設定
2. コントローラーの設定
3. 問い合わせフォーム作成
 1. モデルの作成
 2. viewの作成
4. 問い合わせフォームのMailers

#1. route設定
- scaffoldでcontactsのCRUDを作成する。

```
$docker-compose run web rails g scaffold contacts

$docker-compose run web rake db:migrate
```

/app/views/contactsフォルダの中に、

**・confirm.html.haml**
**・thanks.html.haml**

を作成する。

```ruby:config/routes.rb
resources :contacts
```

となっているので

```ruby:config/routes.rb
resources :contacts do
    collection do
      post 'confirm'
      post 'thanks'
    end
  end
```

とmethodを追記する。

#2. コントローラーの設定

コントローラー画面では3つの項目を追加。

```ruby:/app/controllers/contacts_controller.rb
def index
    # 入力画面を表示
    @contacts = Contact.new
    render :action => 'index'
  end

  def confirm
    @contacts = Contact.new(contact_params)
    if @contacts.valid?
      # OK。確認画面を表示
      render :action => 'confirm'
    else
      # NG。入力画面を再表示
      render :action => 'index'
    end
  end

  def thanks
    # メール送信
    @contacts = Contact.new(params[:contact])
    ContactMailer.registration_confirmation(@contacts).deliver

    # 完了画面を表示
    render :action => 'thanks'
  end

    # パラメーター取得
  def contact_params
      params.fetch(:contact, {}).permit(:id, :terminal, :email, :phone, :message)
  end
```

valid?はValidationの事だそうで、検証した結果を出している模様。

バリデーションに関してはモデルで、
Mailerに関してはメーラークラスで後ほど追記する。


#3. お問い合わせフォームの作成

##1. モデルの作成
フォームで取得するパラメーター、Validationエラーコードを記載する。

```ruby:/app/models/contact.rb
class Contact < ApplicationRecord
    include ActiveModel::Model

    attr_accessor :id, :terminal, :email, :phone, :message

    validates :id, :presence => {:message => 'IDを入力してください'}
    validates :email, :presence => {:message => 'メールアドレスを入力してください'}
    validates :message, :presence => {:message => '内容を入力してください'}
end

```
データベースを使わないモデルなので`ActiveModel`を使って作るらしい。

`attr_accesor`の中にパラメーターを、必須入力にしたい項目を`validates`を使って設定する。


##2. viewの作成
ページに表示させる部分を作成していく。

```ruby:/app/views/contacts/index.html.haml
= form_for(@contacts, :url => {:controller => :contacts, :action => :confirm}) do |f|
  .contact-area
    .contact-contents-title
      %h1 お問い合わせ
     - if @contacts.errors.any?
       .alert.alert-danger{:role => "alert"}
         %strong 入力内容にエラーがあります
         %ul
           - @contacts.errors.each do |attr, msg|
             %li
               = msg
    .contact-wrapper
      .contact-contents
        %table.table.table-dark.table-bordered
          %thead
            %tr
              %td.contact-text1
                あなたのID
                %span.contact-text2 ※必須
              %td.input-area
                = f.text_field :id, :size => "40"
            %tr
              %td.contact-text1 利用している端末
              %td.input-area
                = f.text_field :terminal, :size => "40"
            %tr
              %td.contact-text1 
                メールアドレス
                %span.contact-text2 ※必須
              %td.input-area
                = f.text_field :email, :size => "40"
            %tr
              %td.contact-text1 電話番号
              %td.input-area
                = f.text_field :phone, :size => "40"
            %tr
              %td.contact-text1 
                内容
                %span.contact-text2 ※必須
              %td.input-area
                = f.text_area :message, :class => "input-item", :size => "39x9""
        .actions.btn-wrapper
          = f.submit 'CONFIRM', class:'button btn-lg'
```

`= form_for @contacts, :url => contacts_confirm_path do |f|`

のようなパス指定でもいけるようだが、どうしてもエラーが出るので

`= form_for(@contacts, :url => {:controller => :contacts, :action => :confirm}) do |f|`
コントローラーのアクション指定に変更した。

- `f.text-field`と`f.text-area`の引数設定に苦戦したので引数を記載しておく。

###**f.text-field**

| メソッド            |       要素         |
|:-----------------|------------------:|
| class            | cssのクラスの指定    |
| size             | フォームの幅を指定    |
| maxlength        | 入力可能な最大文字数の指定|

###**f.text-area**

| メソッド            |       要素         |
|:-----------------|------------------:|
| class            | cssのクラスの指定    |
| size             | フォームの幅を指定(幅x行)|
| maxlength        | 入力可能な最大文字数の指定|

```ruby:/app/views/contacts/confirm.html.haml
.contact-area
  .contact-contents-title
    %h1 お問い合わせ
  .contact-wrapper
    .contact-contents

      = form_for(@contacts, :url => {:controller => :contacts, :action => :thanks}) do |f|
        %table.table.table-dark.table-bordered
          %thead
            %tr
              %td.contact-text1
                あなたのID
                %span.contact-text2
              %td.input-area
                = f.hidden_field :id
                = @contacts.id
            %tr
              %td.contact-text1 利用している端末
              %td.input-area
                = f.hidden_field :terminal
                = @contacts.terminal
            %tr
              %td.contact-text1 
                メールアドレス
                %span.contact-text2
              %td.input-area
                = f.hidden_field :email
                = @contacts.email
            %tr
              %td.contact-text1 電話番号
              %td.input-area
                = f.hidden_field :phone
                = @contacts.phone
            %tr
              %td.contact-text1 
                内容
                %span.contact-text2
              %td.input-area
                = f.hidden_field :message
                = simple_format(@contacts.message)
        .actions.btn-wrapper
          = f.submit 'SUBMIT', class:'button btn-lg'
```

```ruby:/app/views/contacts/thanks.html.haml
.contact-area
  .contact-contents-title
    %h1 お問い合わせ
  %p
    お問い合わせ頂きありがとうございました
```

#4. 問い合わせフォームのMailers
先程コントローラーで指定したMailer部分を行なっていく。

Action Mailerは、メールを生成し、メールサーバーへ送信を指示する「仲介」を行ってくれる機能だそうだ。
なのでまずは使用するメールサーバーに合わせて、設定をしておく必要がある。

`config/environments/`にファイルを作ることが多いが、メーラーのパスワード指定があるので、
`config/initializers/`にファイルを作成する。

```ruby:/config/initializers
ActionMailer::Base.delivery_method = :smtp
ActionMailer::Base.smtp_settings = {
  address: 'smtp.gmail.com',
  domain: 'gmail.com',
  port: 587,
  user_name: 'メールアドレス',
  password: 'パスワード',
  authentication: 'plain',
  enable_starttls_auto: true
}
```

メールアドレスとパスワードは、権限を持っているGmailアカウントのものを設定する。

Gmailを利用する場合、Googleのセキュリティ対策のため、Railsアプリケーションからメール送信を行おうとすると、ブロックされる。
なので、Gmail側で`アカウント->セキュリティ->安全性の低いアプリのアクセス`で
安全性の低いアプリの許可を**有効**にする。

次にMailerに必要なファイルを生成する。

```
$docker-compose run web rails g mailer contact_mailer registration_confirmation  
```

上記コマンドをターミナルに打ち込むと

`/app/mailers/`フォルダに
**・contact_mailer.rb**
　　メール送信に使うクラス（ContactMailer）のファイル。

`/app/views/contact_mailer_mailer`に
**・registration_confirmation.haml**
　　メール本文のテンプレートファイル。html形式

**・registration_confirmation.text.haml.text.rb**
　　メール本文のテンプレートファイル。text形式

が生成される。

フォルダ名を`contact_mailer_mailer`から
`contact_mailer`に変更する。

Mailerを下記のように書く。

```ruby:/app/mailers/contact_mailer.rb
class ContactMailer < ActionMailer::Base
  default from:"xxxx@xxxxxx" # 送信元アドレス
  
  def registration_confirmation(contact)
    @contacts = contact
    mail(
      subject: 'お問い合わせを承りました' , #件名
      to: 'xxxx@xxxxxx' #送信先アドレス
      )
  end
end
```
```ruby:/app/views/contact_mailer/registration_confirmation.haml
%p
  Webサイトからお問い合わせがありました。

%p
  あなたのID: 
  = @contacts.id
%p
  利用している端末: 
  = @contacts.terminal
%p
  メールアドレス: 
  = @contacts.email
%p
  電話番号: 
  = @contacts.phone
%p
  内容: 
  = @contacts.message

```

```/app/views/contact_mailer/registration_confirmation.text.haml.text.rb
Webサイトからお問い合わせがありました。

========================
あなたのID: 
= @contacts.id
利用している端末: 
= @contacts.terminal
メールアドレス: 
= @contacts.email
電話番号: 
= @contacts.phone
内容: 
= @contacts.message
========================
```

メールの送信形式をtext形式にしたければ前者、html形式にしたければ、後者を作成する。
両方あった場合は、メーラーは両方をまとめたメール（マルチパートメール）を送付し、受信する相手の環境に合わせてどちらかが表示される。

問い合わせフォームページから、各項目を入力し、
フォームを送信し、フォーム内容がメールに届いている事を確認する。

以上になる。

#参考にしたページ

https://www.imd-net.com/column/1731/
https://web-camp.io/magazine/archives/19143