【Rails】deviseが最低限使えるようになるためのポイント


インストール

Gemfile
gem 'devise'
$ bundle install
$ rails g devise:install

config/initializers/devise.rbconfig/locales/devise.en.ymlの2つのファイルが作成され、以下のメッセージが表示される

原文
Depending on your application's configuration some manual setup may be required:
  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.
     * Required for all applications. *
  2. Ensure you have defined root_url to *something* in your config/routes.rb.
     For example:
       root to: "home#index"
     * Not required for API-only Applications *
  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>
     * Not required for API-only Applications *
  4. You can copy Devise views (for customization) to your app by running:
       rails g devise:views
     * Not required *
ざっくり翻訳
以下の設定が必要だよ
1. config/environments/development.rbにデフォルトのURLを設定する。
   書き方はこんな感じ↓
   config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
   上記の例は開発環境用だから、本番環境では実際のURLがセットされるようにする
→ 新規会員登録メール、パスワード再設定メールにサイトのURLを埋め込む時とかに使うっぽい。

2. config/route.rbにroot_urlをセットする(普通してる)

3. app/views/layouts/application.html.erbにflashメッセージの表示エリアを作る
   書き方はこんな感じ↓
   <p class="notice"><%= notice %></p>
   <p class="alert"><%= alert %></p>

4. deviseが自動生成するページのデザインをカスタマイズしたい場合、rails g devise:viewsで生成されるフ 
   ァイルを編集する

ユーザーテーブルを作成

$ rails g devise User # rails g devise モデル名
  1. app/models/user.rbの生成
  2. マイグレーションファイルの作成
  3. config/routes.rbdevise_for :usersという記述が追加され、deviseで使うルーティングが作成される

マイグレーションファイルには、デフォルトでメールアドレスやパスワードなど、いろんな項目が設定されている。
必要に応じてカラムを追加。ここではnameというカラムを追加。

db/migrate/timestamp_devise_create_users.rb
class DeviseCreateUsers < ActiveRecord::Migration[5.2]
  def change
    create_table :users do |t|
      t.string :name # 追加
      t.string :email,              null: false, default: ""
      t.string :encrypted_password, null: false, default: ""
      t.string   :reset_password_token
      t.datetime :reset_password_sent_at
      t.datetime :remember_created_at
      t.string :name      t.timestamps null: false
    end
    add_index :users, :email,                unique: true
    add_index :users, :reset_password_token, unique: true
  end
end
$ rails db:migrate

strong parametersを設定

deviseのコントローラーは、ライブラリ側で用意されているので、直接修正できない。
だからdeviseのコントローラーに修正が必要なときは、application_controllerに書く。

今回nameというカラムを追加したので、configure_permitted_parametersを上書きしてsignup時にnameを扱えるようにする。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected

  def configure_permitted_parameters # deviseで使われているstrong_parameterを上書き
    devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
  end
end

before_actionでログインチェック

application_controllerにbefore_action :authenticate_user!をセットして、ログインしないと見れないページにログインせずにアクセスした場合、ログインページにリダイレクトするように設定。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  before_action :authenticate_user!
  # 省略  
end

※ログイン前に見れるページがある場合、そのページのcontrollerにskip_before_action :authenticate_user!を設定する。

この時点で
http://開発環境のIP/users/signupにアクセスすると、ユーザー登録画面が表示される
http://開発環境のIP/users/sign_inにアクセスすると、ログイン画面が表示される
http://開発環境のIP/users/sign_outにdeleteでアクセスすると、ログアウトする

これでひとまずユーザー登録、ログイン、ログアウト処理が完成。(※メール認証挟まないからまだ実運用はきつめ)

画面を編集する

deviseをインストールした時のメッセージ[4]にもあったようにviewファイルを生成してデザインや項目をカスタマイズする。

$ rails g devise:views

viewファイルがたくさん生成される。今回はユーザー登録時の画面にname項目を追加。

app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>

<%= form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
  <%= render "devise/shared/error_messages", resource: resource %>
  <!-- #以下を追加 -->
  <div class="field">
    <%= f.label :name %><br />
    <%= f.text_field :name, autofocus: true %>
  </div>

ログインしているかどうかで表示を分ける

<ul>
<% if user_signed_in? %>
  <li><%= link_to "ログアウト", destroy_user_session_path, method: :delete %></li>
<% else %>
  <li><%= link_to "新規登録", new_user_registration_path %></li>
  <li><%= link_to "ログイン", new_user_session_path %></li>
<% end %>
</ul>

form_forform_withに変更

deviseのformはデフォルトでform_forを使っているのでより新しい書き方のform_withに修正

app/views/devise/registrations/new.html.erb
<h2>Sign up</h2>
<%= #削除 form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| %>
<%= form_with model: @user, url: user_registration_path, id: 'new_user', class: 'new_user', local: true do |f| %>
app/views/devise/sessions/new.html.erb
<h2>Log in</h2>
<%= #削除 form_for(resource, as: resource_name, url: session_path(resource_name)) do |f| %>
<%= form_with model: @user, url: user_session_path, local: true do |f| %>

ログイン後に遷移する画面を変更

デフォルトだとroot_pathに遷移するようになっているようです。メソッドを上書きしてuser_path(user)に設定してみます。

app/controllers/application_controller.rb
class ApplicationController < ActionController::Base
  #省略
  def after_sign_in_path_for(resource)
    user_path(resource)
  end
  #省略
end 

ユーザー詳細ページを作成

これはdevise無視して勝手にcontrollerやviewを作る。編集とか削除とかも同じ、deviseは気にしないで作る。

$ rails g controller users show
app/controllers/users_controller.rb
class UsersController < ApplicationController
  def show
    @user = User.find(params[:id])
  end
end
config/routes.rb
resources :users, only: %i[show]
app/views/users/show.html.erb
<h2>ユーザー詳細</h2>
<p><%= @user.name %></p>
<p><%= @user.email %></p>

remember me機能

デフォルトで使える。
remember meにチェックしてログインするとusersテーブルのremember_created_atカラムに日付が入る。この日付から一定期間(デフォルトで2週間)は、ブラウザを閉じてもcookieに保存してある情報で自動ログインする。

ログアウトしたり、remember meにチェックを入れずにログインをしたタイミングでremember_created_atnilが入る。

[Rails5]Deviseのログイン判定 | ゆるりエンジニア

パスワードリセット機能

デフォルトで使える。
ただメール送信機能ができていない場合メールは送られないので、サーバーのログから、送られるメールの文面(とパスワード再設定用のURL)を確認してアクセスする必要がある。

ヘルパーいろいろ

current_user # ログイン中のユーザーのオブジェクト
user_signed_in? # ログインしてるか確認

参考