Rails5 Cloud9でdeviseのメール送信用サーバーsmtpの設定まで

###Rails5 Cloud9でdeviseのメール送信用サーバーsmtpの設定まで
Railsでwebアプリケーションの開発に必要なユーザー登録やログイン機能を実装するにはdeviseというgemを使います。

登録方法として、ユーザーのメールアドレスに確認メールを送信し、受け取ったユーザーがワンクリックで登録を行なうといったよくあるやつが可能になります。

今回はAWSのcloud9環境において、smtpサーバーの設定に挑戦しましたので、記しておきたいと思います。
####手順
- AWS cloud9でsmtpサーバーを使うためにGmailを使用する
- アプリパスワードを取得する
- 補足
- deviseを導入する
- 認証メールのURL設定
- deviseのviewsを生成する
- Userモデルを作成する
- migrationファイルを確認し、コメントアウトを外す
- rake db:migrateでテーブルを作成する
- 補足
- メール認証モジュールを読み込む
- smtpサーバーの設定
- トークンの設定
- 登録テストを行う


###AWS Cloud9でsmtpサーバーを使うためにGmailを使用する
smtpサーバーとはメールを送信する時に使用する機能を持ったメールサーバーです。メールを受信する機能を持ったサーバーはpopサーバーと言います。Simple Mail Transfer Protocol の略になります。

設定方法ですが、Cloud9自体がGoogle Cloud Engineを利用しており、Gmailアカウント以外の通信を許可しておりません。設定にGmailを必要としますので、捨てアカウントを作成してください。
通信の許可を得るために、アプリパスワードを使用します。

Gmailを使った必要なプロセスとしましては、二段階認証を行なったgoogleアカウントでアプリパスワードを発行します。まずはアプリパスワードを取得しましょう。
###アプリパスワードを取得する
[gmailアプリパスワード](https://support.google.com/mail/answer/185833?hl=ja)
`アプリパスワードの生成方法`をクリックします
<img width="500" alt="app_password01.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/7302b961-19c9-6e61-7ef6-eaf0af5885a1.png">

`googleアカウント`をクリックします

<img width="500"alt="app_password02.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/a79d667f-f584-deeb-86bc-e45d1f1a2d9d.png">

`セキュリティ`をクリックします

<img width="500" alt="app_password03.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/f0684433-6f0b-e7c8-9ec1-3c643f866f68.png">

`二段階認証`をクリックします

<img width="500" alt="app_password04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/be82b9a6-a953-e408-a99c-5f7447cf440e.png">

`開始`をクリックします

<img width="1216" alt="app_password05.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/8a40ef0e-273a-1e74-1393-730d5a7a822c.png">

認証にスマホを使用します。`今すぐ送信`をクリックします。

<img width="500" alt="app_password06.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/dbde6029-739d-4b2d-1161-addb5c5f07c0.png">

`google`からメッセージが送信されます

<img width="500" alt="app_password07.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/9570f732-4b3f-da13-bb54-133f8a788869.png">

`送信`をクリックします

<img width="500" alt="app_password08.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/3fe78233-b9c5-ef70-0244-6097d171730f.png">

スマホに受信されたパスコードを入力します。`次へ`をクリックします。

<img width="1216" alt="app_password09.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/3b2f2cd0-b3a0-3c4c-7ea5-9b1c3f2b37cc.png">

認証されたら二段階認証を`有効`にします

<img width="1216" alt="app_password10.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/8703f382-bdc5-52d7-559e-c3a46325650b.png">

googleアカウントに戻って二段階認証が`on`であることを確認したら、`アプリパスワード`をクリックします

<img width="500" alt="app_password11.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/60575fd8-8a5b-88cf-8e70-8b92a9b94fd1.png">

アプリパスワードのページにアクセスする際にパスワードやスマホを使った認証を行います。それらのプロセスを進めます。
表示されたら`アプリを選択`をクリックします。その他を選択します。

<img width="500" alt="app_password12.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/231d5092-6141-2b07-24e4-76be833d4f01.png">

名称を決めます。開発中のアプリケーション名でも良いですね。`生成`をクリックします

<img width="500" alt="app_password13.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/86ca40a6-26ea-095d-3415-0743f6187c44.png">

パスワードが生成されました。こちらのパスワードを開発環境で使用します。
忘れない様に保存します。

<img width="500" alt="app_password14.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/91b36c07-acf6-0ed0-f761-ffce4fdc3cd9.png">

確認が取れました。

<img width="1216" alt="スクリーンショット 2019-06-29 6.27.04.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/328651/6ee503ea-d4f4-31f3-2d2b-ea6a69472396.png">
これで二段階認証のプロセスとアプリパスワードの取得は完了です。
###補足
アプリパスワードを使用しない場合は有効化を無効にしておくと良いでしょう。
その手続きは先ほど行なったスマートフォンなどでのやり取りが必要になります。
発行されたパスワードはこの手続きでは確認取れませんので、発行した段階で忘れない様に保存しましょう。
##deviseを導入する
<strong>前提として、dbとサーバーは導入済みとします。</strong>
gemファイルにインストールしたい<strong>devise</strong>を記述します。

```ruby:myapp/gemfile
gem 'devise'

```
作業ディレクトリでインストールします。

```terminal
~/environment/myapp $ 
~/environment/myapp $  bundle install
```
<strong>devise</strong>の設定ファイルを生成します。

```terminal
~/environment/myapp $ rails g devise:install
```
<strong>新規作成されるファイル

- config/initializers/devise.rb
- config/locales/devise.en.yml

|  ファイル名 |  概要 |
| --- | ----|
| config/initializers/devise.rb  | deviseに関する設定ファイル。カスタマイズ時に使用します  |
| config/locales/devise.en.yml | 表示されるバリデーションがデフォルトで英語になっています|

### 認証メールのURL設定

登録に使用されたメールアドレスにアプリケーションから認証ファイルがメールで送信されます。
ここでは認証ファイルに記載されるはずのリンク先を設定します。要はアプリケーションの開発先のトップアドレスです。

```ruby:config/environments/development.rb
Rails.application.configure do
#省略
#一番下に記述します
config.action_mailer.default_url_options = { protocol: 'https', host:'https://~~~'}
end
```
### フラッシュメッセージのタグを記述する

フラッシュメッセージとはログイン時やログアウトの時に、一時的にだす「ログインしました」の様なメッセージのことです。`devise`のインストール時にターミナルに表示されていた様に記述することを推奨されています。一般的には`app/view/layouts/application.html.erb`に埋め込む様です。

```ruby:app/views/layouts/application.html.erb
<p class="notice"><%= notice%></p>
<p class="alert"><%= alert %></p>
#bootstrapの場合は
<%= bootstrap_flash %>

```
###deviseのviewsを生成する
サインアップやログイン、パスワードの再設定など必要なファイルがあらかじめ用意されています。
それらをカスタマズして作成していくことがほとんどになると思います。

```terminal
$ cd myapp
$ pwd 
$ rails g devise:views
```
<strong>新規作成されるファイル</strong>
- app/views/devise/mailer/confirmation_instructions.html.erb
- app/views/devise/mailer/reset_password_instructions.html.erb
- app/views/devise/mailer/unlock_instructions.html.erb
- app/views/devise/passwords/edit.html.erb
- app/views/devise/passwords.new.html.erb
- app/views/devise/registrations/edit.html.erb
- app/views/devise/registrations/new.html.erb
- app/views/devise/sessions/new.html.erb
- app/views/devise/shared/_links.html.erb
- app/views/devise/unlocks/new.html.erb
###Userモデルを作成する
登録者用のモデルを用意します。`rails g model model名`がありますが、`devise`用のモデルの作成コマンドを使用します。
`rails g devise model名`により、deviseを利用するために初期設定されたファイルを生成することが出来ます。今回はUserモデルを生成します。`rake db:migrate`をすぐに実行しないで下さい。

```terminal
$ cd myapp
$ pwd
$ rails g devise user
```

<strong>新規作成されるファイル</strong>
- app/models/user.rb
- db/migrate/xxxxx_devise_create_users.rb
- test/fixtueres/users.yml
- test/models/user_test.rb

<strong>更新されるファイル</strong>
- config/routes.rb

```ruby:config/routes.rb
Rails.application.routes.draw do
 devise_for :users
 roots to: "top#index"
end
```
<strong>devise_for</strong>
サインインやログイン周りのルーティングを生成してくれます。`rake routes`を実行しルーティングを確認します。

```terminal 
$ rake routes
```
### migrationファイルを確認し、コメントアウトを外す
`rails g devise user`により生成されたmigrationファイルを確認します。

```ruby:db/migrate/xxxxxx_devise_create_users.rb
# frozen_string_literal: true

class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      ## Database authenticatable
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""

      ## Recoverable
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at

      ## Rememberable
      t.datetime :remember_created_at

      # Trackable
      t.integer  :sign_in_count, default: 0, null: false
      t.datetime :current_sign_in_at
      t.datetime :last_sign_in_at
      t.string   :current_sign_in_ip
      t.string   :last_sign_in_ip

      # Confirmable
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ## Lockable
      # t.integer  :failed_attempts, default: 0, null: false # Only if lock strategy is :failed_attempts
      # t.string   :unlock_token # Only if unlock strategy is :email or :both
      # t.datetime :locked_at


      t.timestamps null: false
    end

    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
    # add_index :users, :confirmation_token,   unique: true
    # add_index :users, :unlock_token,         unique: true
  end
end

```
`#Trackable` と `#Confirmable`のコメントアウトを外します。
こちらは認証メールのトークンや再設定のカラムなど、登録周りのカラムがデフォルトでコメントアウトされています。`rake db:migrate`する前に外しましょう。
## rake db:migrateでテーブルを作成します
設定したmigrationファイルを実行してテーブルやカラムをdbに作成します。

```terminal
$ rake db:migrate
```
サーバーを再起動します

###補足
登録ページにアクセスするにはtop pageアドレスに`/users/sign_in`をつけます。ログインしなければtop pageにアクセス出来ない様にする方法を取ることがあると思います。smtpメールとの関連程度に記述します。
<strong>authenticate_user!</strong>
authenticate_user!はdeviseのメソッドです。
ユーザーがログインしているか確認し、そうでない場合はログインページに飛ばします。このサービスはどんな場合でも優先されるものとするならば、Application_Controller.rbに設定すると有効だそうです。その他のControllerが継承しているからでしょう。

```ruby:app/controllers/application_controller.rb
before_action :authenticate_user!
protect_from_forgery with: :exception
end
```
サーバーを再起動します。
### メール認証モジュールを読み込む
今回ログインに使用するモデルは`User`モデルです。`devise`のメール認証を有効にするためにはdeviseのモジュールをモデルに読み込んでもらいます。

```ruby:app/models/user.rb
class User < ApplicationRecord
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
  devise :database_authenticatable, 
         :registerable,
         :recoverable,
         :trackable,
         :rememberable,
         :validatable,
         :confirmable

end
```
### smtpサーバーの設定
開発段階での設定となりますが、gmailアドレスやパスワードを含みます。Gitを使用している場合は公開しない様に注意しましょう。

```ruby:config/environments/development.rb
Rails.application.configure do
 config.file_watcher = ActiveSupport::EventedFileUpdateChecker
  config.action_mailer.default_url_options = { protocol: 'https', host: 'https://xxxxx.vfs.cloud9.ap-southeast-1.amazonaws.com'}
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :enable_starttls_auto => true,
    :address => "smtp.gmail.com",
    :port => 587,
    :domain => 'smtp.gmail.com',
    :user_name => "xxx@gmail.com",
    :password => "取得したアプリパスワード",
    :authentication => 'login'
  }
end
```
次にアプリパスワードの取得に使用したGmailを記述します。

```ruby:config/initialiezers/devise.rb
config.mailer_sender = 'xxx@gmail.com'
```
### トークンの設定
トークンの設定を下記の通りに変更しました。[stackoverflow](https://stackoverflow.com/questions/18626544/devise-confirmation-token-is-invalid-when-user-signs-up)と[plataformatec/devise](https://github.com/plataformatec/devise/commit/143794d701bcd7b8c900c5bb8a216026c3c68afc#diff-522de69e2ba667457d5f3e159bc87789)を参考にしました。変更する前はエラーが出ました。E-mail内のトークンとdb内のトークンが一致することが必要な様です。

```ruby:devise/mailer/confirmation_instructions.html.erb
<p>Welcome <%= @email %>!</p>
<p>You can confirm your account email through the link below:</p>
<!--@tokenを変更した-->
<p><%= link_to 'Confirm my account', confirmation_url(@resource, :confirmation_token => @token) %></p>
```
## 登録テストを行う
登録方法として、ユーザーのメールアドレスに確認メールを送信し、受け取ったユーザーがワンクリックで登録を行なうをテストしましょう。
登録したメールアドレスに上記のHTMLファイルが送信されます。`confirm my account`をクリックしてエラーが出ずにログインページに飛ばされた、そのままログイン出来たら成功です。

##まとめ
Rails5 cloud 9でdeviseのメール送信用サーバーsmtpの設定でした。
deviseのログイン機能はとても便利な機能を持っています。カスタマイズも色々と出来そうなので色々挑戦していきたいと思います。