Railsアプリにdeviseを導入する手順

##deviseとは
認証機能を簡単に実装することができます。他にもいろんなことができるのでとても便利です！
##deviseのインストール
Gemfileにgemを追加しbundle installする。

```rb:Gemfile
gem 'devise'
```

```
$ bundle install
```
次にこのコマンドでdeviseの設定ファイルを作成

```rb
$ rails g devise:install
```
そしたらこのような画面が出てくると思います。設定していきましょう。

```

===============================================================================
 
Some setup you must do manually if you haven't yet:
 
  1. Ensure you have defined default url options in your environments files. Here
     is an example of default_url_options appropriate for a development environment
     in config/environments/development.rb:
 
       config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
 
     In production, :host should be set to the actual host of your application.
 
  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:
 
       root to: "home#index"
 
  3. Ensure you have flash messages in app/views/layouts/application.html.erb.
     For example:
 
       <p class="notice"><%= notice %></p>
       <p class="alert"><%= alert %></p>
 
  4. You can copy Devise views (for customization) to your app by running:
 
       rails g devise:views
 
===============================================================================
```
**1. 本登録メールに記載されるURLのホストの指定を行う。**

```rb:config/environments/development.rb
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
```
**2.  routes.rbにてroot_urlを設定する。**
ログイン、ログアウトした時などにこのroot_urlにリダイレクトする。これはあくまで例なので変更できます。もし自分でroot_urlを設定していたらそこにリダイレクトします。

```rb:config/routes.rb
root to: "home#index"
```
**3. エラーメッセージ用のタグをapplication.html.erbに追記する。**
<%= yield %>の上に書くことが多いです。

```rb:app/views/layouts/application.html.erb
<p class="notice"><%= notice %></p>
<p class="alert"><%= alert %></p>

#上の様に記述してもいいし、これでもいい。
<% flash.each do |key, value| %>
　　<%= content_tag(:div, value, class: "#{key}") %>
<% end %>
or
<% if notice %>
  <p class="alert alert-success"><%= notice %></p>
<% end %>
<% if alert %>
  <p class="alert alert-danger"><%= alert %></p>
<% end %>
```
**4. もしdeviseのViewをカスタマイズしたい場合は、下記コマンドで生成してからカスタマイズする。**
後でカスタマイズします。
##認証機能用のファイルを作成
下記コマンドを実行するだけで認証機能に必要なファイルが生成されます。
Userのところは任意ですが、Userが一般的です。Model名になります。

```rb
$ rails g devise User
```
Userモデルが生成されるので、一応中身をのせておきます。いろんな機能を追加できるので、やってみたければ調べて追加してみて下さい。今回はデフォルトのままにしておきます。

```rb:app/models/user.rb
class User < ActiveRecord::Base
  # Include default devise modules. Others available are:
  # :confirmable, :lockable, :timeoutable and :omniauthable
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :trackable, :validatable
end
```
マイグレーションを忘れずに！

```rb
$ rails db:migrate
```
これで最低限の設定は終了しました！
動くようになっているはずです。

**deviseによって使えるようになるヘルパーメソッド**

| メソッド         | 使い方           |
|:-----------------|:-----------------|
| before_action :authenticate_user!   |   Controllerに設定して、ログイン済ユーザーのみにアクセスを許可する。               |
| user_signed_in?	           |     ユーザーがサインイン済かどうかを判定する。Controller、Viewで利用可能。             |                  
| current_user             |          サインインしているユーザーを取得する。Controller、Viewで利用可能。       |
| user_session               |            ユーザーのセッション情報にアクセスする。     |
Model名をUser以外にしてる場合は、userのところを代わりにそのModel名に変更してください。

**Viewを設定**
Viewをカスタマイズしたいときにやります。たぶんカスタマイズすることになるので作っておきましょう。

```rb
# app/views/users下にViewが生成される。←こっちのコマンドでViewを生成しましょう。
$ rails g devise:views users

# これだとapp/views/devise下にViewが生成される。
$ rails g devise:views
```
できたら、config/initializers/devise.rbを編集します。理由は、deviseのデフォルトのスコープが、app/views/deviseを見に行くようになっているからです。下のように設定すると、app/views/usersを見に行くようにしてくれます。

```rb:config/initializers/devise.rb
# コメントをはずして、trueに変更。
config.scoped_views = true
```

**Controllerの設定**
Contorollerをカスタマイズしたときにやります。Controllerの場合ルーティングも変更する必要があります。下のコマンドでControllerを生成します。生成されたファイルには何も書かれていないですが、deviseのコントローラーを継承したカスタムControllerが生成されます。なのでdeviseが提供しているヘルパーメソッドはそのまま使えます。

```rb
$ rails g devise:controllers users
```
ルーティングを変更する。

```rb:config/root.rb
devise_for :users, controllers: {
  registrations: 'users/registrations',
  sessions: 'users/sessions'
}
```

**リダイレクト先を変更する**
デフォルトの状態では、新規登録やログイン、ログアウトしたときにroot_urlにリダイレクトします。このリダイレクト先を変更できるので設定していきます。Controllerを設定しておく必要があるので、上の手順に従ってやっておいて下さい。この設定は、app/controllers/applictaion_controller.rbにまとめて書くこともできるのですが、メソッドはなるべく個々のコントローラで定義し、複数のコントローラで使い回すメソッドのみapplication_controllerで定義するほうがいいので、今回は別々のコントローラーに定義していきたいと思います。

・新規登録後とアカウント変更後のリダイレクト先

```rb:app/controllers/users/registrations_controller.rb
#新規登録後のリダイレクト先
def after_sign_up_path_for(resource)
  リダイレクト先のパス(root_path, users_pathなど)
end

#アカウント変更後のリダイレクト先
def after_update_path_for(resource)
  リダイレクト先のパス
end
```

・ログイン、ログアウト後のリダイレクト先

```rb:app/controllers/users/sessions_controller.rb
#ログイン後のリダイレクト先
def after_sign_in_path_for(resource)
  リダイレクト先のパス
end 

#ログアウト後のリダイレクト先
def after_sign_out_path_for(resource)
  リダイレクト先のパス
end 
```
これで変更できました！
##カラムを追加する
ここからは、任意の作業になりますが、使うことが多いことなのでメモしておきます。
deviseはデフォルトではemailカラムとpasswordカラムしか持っていないので、別のカラムを追加したいときの手順を書いていきます。今回は、nameカラムを追加しようと思います。

**nameカラムを追加する**

```rb
$ rails g migration add_name_to_users name:string
```
生成されたマイグレーションファイルを少し変更。ここは任意ですので自分の設計に合わせて行ってください。
名前の入力を必須にし、デフォルトを空にしました。マイグレートを忘れずに。

```rb
class AddColumnToUsers < ActiveRecord::Migration
  def change
    add_column :users, :name, :string, null: false, default: ""
  end
end
```

```rb
$ rails db:migrate
```

**データベース設定**
これを行うことで、nameカラムもストロングパラメーターの対象になります。

```rb:app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  # Prevent CSRF attacks by raising an exception.
  # For APIs, you may want to use :null_session instead.
  protect_from_forgery with: :exception

# ↓ここから追加↓
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

    def configure_permitted_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:name]) # 新規登録するときに適応
      devise_parameter_sanitizer.permit(:account_update, keys: [:name]) # アカウント内容を変更するとき適応
    end
# ↑ここまで↑

end
```

**Viewをカスタマイズ**
新規登録とアカウント内容を変更するときのViewをカスタマイズする。

```rb:app/views/users/registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= devise_error_messages! %>

<!-- ↓ここから追加↓ -->

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>

<!-- ↑ここまで↑ -->

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email %>
  </div>
.
.
.
.
```

```rb:app/views/users/registrations/edit.html.erb
<!-- ↓ここから追加↓ -->

  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>

<!-- ↑ここまで↑ -->

  <div class="field">
    <%= f.label :email %><br />
    <%= f.email_field :email %>
  </div>
.
.
.
.
```
これで終了です！
##日本語化する
deviseで生成されたViewやエラーメッセージはデフォルトでは英語なので、日本語に変更しましょう。

**ローケルを日本語にする**
この設定をしないと日本語になってくれません。

```rb:config/application.rb
config.i18n.default_locale = :ja # これを記述
```

**gemを追加**
必要なgemを追加してbundle installします。

```rb:Gemfile
gem 'devise-i18n'

# このgemがないとrails g devise:i18n:locale jaができないことがあるようです。
# devise-i18nに機能が統一されたようですが理由は分かりません。
gem 'devise-i18n-views'
```

```
$ bundle install
```

**Viewを生成し直す**
rails g devise:viewsで作成される View は I18n に対応していないので、生成し直します。

```rb
$ rails g devise:i18n:views users
```

**ローケルファイルを生成**
View のスコープを User に変更してる場合はファイル内のdeviseという記述をusersに変更しましょう。カラムを追加してる場合はその分も追加しておきます。これで、deviseのエラーメッセージやフォームのラベルなどが日本語になるはずです。

```rb
$ rails g devise:i18n:locale ja

# 必要ないかもしれませんがen版も生成できます。
# この場合もともとあったローケルファイルは削除しておきましょう。
$ rails g devise:i18n:locale en
$ rm config/locales/devise.en.yml
```

**ローケルファイルの変更。**

```rb:config/locales/devise.views.ja.yml
ja:
  activerecord:
    attributes:
      user:
        name: "名前" #カラムを追加した場合はここに随時追加していく
        confirmation_sent_at: "パスワード確認送信時刻"
        confirmation_token: "パスワード確認用トークン"
        confirmed_at: "パスワード確認時刻"
        created_at: "作成日"
        current_password: "現在のパスワード"
        current_sign_in_at: "現在のログイン時刻"
        current_sign_in_ip: "現在のログインIPアドレス"
        email: "Eメール"
        encrypted_password: "暗号化パスワード"
        failed_attempts: "失敗したログイン試行回数"
        last_sign_in_at: "最終ログイン時刻"
        last_sign_in_ip: "最終ログインIPアドレス"
        locked_at: "ロック時刻"
        password: "パスワード"
        password_confirmation: "パスワード（確認用）"
        remember_created_at: "ログイン記憶時刻"
        remember_me: "ログインを記憶する"
        reset_password_sent_at: "パスワードリセット送信時刻"
        reset_password_token: "パスワードリセット用トークン"
        sign_in_count: "ログイン回数"
        unconfirmed_email: "未確認Eメール"
        unlock_token: "ロック解除用トークン"
        updated_at: "更新日"
    models:
      user: "ユーザー"
  users: # ここがdeviseになってるはずなのでusersに変更
    confirmations:
      confirmed: "アカウントを登録しました。"
      new:
        resend_confirmation_instructions: "アカウント確認メール再送"
      send_instructions: "アカウントの有効化について数分以内にメールでご連絡します。"
      send_paranoid_instructions: "メールアドレスが登録済みの場合、本人確認用のメールが数分以内に送信されます。"
    failure:
      already_authenticated: "すでにログインしています。"
      inactive: "アカウントが有効化されていません。メールに記載された手順にしたがって、アカウントを有効化してください。"
      invalid: "%{authentication_keys}またはパスワードが違います。"
      last_attempt: "もう一回誤るとアカウントがロックされます。"
      locked: "アカウントは凍結されています。"
      not_found_in_database: "%{authentication_keys}またはパスワードが違います。"
      timeout: "セッションがタイムアウトしました。もう一度ログインしてください。"
      unauthenticated: "アカウント登録もしくはログインしてください。"
      unconfirmed: "メールアドレスの本人確認が必要です。"
    mailer:
      confirmation_instructions:
        action: "メールアドレスの確認"
        greeting: "%{recipient}様"
        instruction: "以下のリンクをクリックし、メールアドレスの確認手続を完了させてください。"
        subject: "メールアドレス確認メール"
      email_changed:
        greeting: "こんにちは、%{recipient}様。"
        message: "あなたのメール変更（%{email}）のお知らせいたします。"
        subject: "メール変更完了。"
      password_change:
        greeting: "%{recipient}様"
        message: "パスワードが再設定されたことを通知します。"
        subject: "パスワードの変更について"
      reset_password_instructions:
        action: "パスワード変更"
        greeting: "%{recipient}様"
        instruction: "パスワード再設定の依頼を受けたため、メールを送信しています。下のリンクからパスワードの再設定ができます。"
        instruction_2: "パスワード再設定の依頼をしていない場合、このメールを無視してください。"
        instruction_3: "パスワードの再設定は、上のリンクから新しいパスワードを登録するまで完了しません。"
        subject: "パスワードの再設定について"
      unlock_instructions:
        action: "アカウントのロック解除"
        greeting: "%{recipient}様"
        instruction: "アカウントのロックを解除するには下のリンクをクリックしてください。"
        message: "ログイン失敗が繰り返されたため、アカウントはロックされています。"
        subject: "アカウントの凍結解除について"
    omniauth_callbacks:
      failure: "%{kind} アカウントによる認証に失敗しました。理由：（%{reason}）"
      success: "%{kind} アカウントによる認証に成功しました。"
    passwords:
      edit:
        change_my_password: "パスワードを変更する"
        change_your_password: "パスワードを変更"
        confirm_new_password: "確認用新しいパスワード"
        new_password: " 新しいパスワード"
      new:
        forgot_your_password: "パスワードを忘れましたか?"
        send_me_reset_password_instructions: "パスワードの再設定方法を送信する"
      no_token: "このページにはアクセスできません。パスワード再設定メールのリンクからアクセスされた場合には、URL をご確認ください。"
      send_instructions: "パスワードの再設定について数分以内にメールでご連絡いたします。"
      send_paranoid_instructions: "メールアドレスが登録済みの場合、パスワード再設定用のメールが数分以内に送信されます。"
      updated: "パスワードが正しく変更されました。"
      updated_not_active: "パスワードが正しく変更されました。"
    registrations:
      destroyed: "アカウントを削除しました。またのご利用をお待ちしております。"
      edit:
        are_you_sure: "本当によろしいですか?"
        cancel_my_account: "アカウント削除"
        currently_waiting_confirmation_for_email: "%{email} の確認待ち"
        leave_blank_if_you_don_t_want_to_change_it: "空欄のままなら変更しません"
        title: "%{resource}編集"
        unhappy: "気に入りません"
        update: "更新"
        we_need_your_current_password_to_confirm_your_changes: "変更を反映するには現在のパスワードを入力してください"
      new:
        sign_up: "アカウント登録"
      signed_up: "アカウント登録が完了しました。"
      signed_up_but_inactive: "ログインするためには、アカウントを有効化してください。"
      signed_up_but_locked: "アカウントが凍結されているためログインできません。"
      signed_up_but_unconfirmed: "本人確認用のメールを送信しました。メール内のリンクからアカウントを有効化させてください。"
      update_needs_confirmation: "アカウント情報を変更しました。変更されたメールアドレスの本人確認のため、本人確認用メールより確認処理をおこなってください。"
      updated: "アカウント情報を変更しました。"
      updated_but_not_signed_in: "あなたのアカウントは正常に更新されましたが、パスワードが変更されたため、再度ログインしてください。"
    sessions:
      already_signed_out: "既にログアウト済みです。"
      new:
        sign_in: "ログイン"
      signed_in: "ログインしました。"
      signed_out: "ログアウトしました。"
    shared:
      links:
        back: "戻る"
        didn_t_receive_confirmation_instructions: "アカウント確認のメールを受け取っていませんか?"
        didn_t_receive_unlock_instructions: "アカウントの凍結解除方法のメールを受け取っていませんか?"
        forgot_your_password: "パスワードを忘れましたか?"
        sign_in: "ログイン"
        sign_in_with_provider: "%{provider}でログイン"
        sign_up: "アカウント登録"
      minimum_password_length: "（%{count}字以上）"
    unlocks:
      new:
        resend_unlock_instructions: "アカウントの凍結解除方法を再送する"
      send_instructions: "アカウントの凍結解除方法を数分以内にメールでご連絡します。"
      send_paranoid_instructions: "アカウントが見つかった場合、アカウントの凍結解除方法を数分以内にメールでご連絡します。"
      unlocked: "アカウントを凍結解除しました。"
  errors:
    messages:
      already_confirmed: "は既に登録済みです。ログインしてください。"
      confirmation_period_expired: "の期限が切れました。%{period} までに確認する必要があります。 新しくリクエストしてください。"
      expired: "の有効期限が切れました。新しくリクエストしてください。"
      not_found: "は見つかりませんでした。"
      not_locked: "は凍結されていません。"
      not_saved:
        one: "エラーが発生したため %{resource} は保存されませんでした。"
        other: "%{count} 件のエラーが発生したため %{resource} は保存されませんでした。"
      taken: "は既に使用されています。"
      blank: "が入力されていません。"
      too_short: "は%{count}文字以上に設定して下さい。"
      too_long: "は%{count}文字以下に設定して下さい。"
      invalid: "は有効でありません。"
      confirmation: "が内容とあっていません。"
```
これで終了です！
deviseではまだまだ多くの機能を追加できるので、気になったらやってみてもいいかもしれないです。みなさんのお役に立てれば幸いです。