Ruby on Rails:devise gem で認証機能を導入する

devise gem 概要

devise は Warden に基づく Rails 用の柔軟な認証ソリューション。パスワードはハッシュしてデータベースに保存してくれる。要は、認証するサービスを提供できるようにしてくれる。

devise gem の導入

Gemfile に gem 'devise' を追加し bundle install を実行する。そして、rails generate devise:install コマンドを叩き、ジェネレータを実行する。

ジェネレータを実行すると次のファイルが生成される。

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

config/environments/development.rbに次のコードを追加する。

config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }

次にモデルを生成するために、まずは User 用のマイグレーションファイルを生成する。

% rails generate devise User

ジェネレータに生成されたコード(****_devise_create_users.rb)に対して、今回追加したい属性を追加する。とりあえず、下記を追加。

      ## User data
      t.string :post_code
      t.string :address
      t.string :self_introduction

そして、下記コマンドでデータベースを生成して、中身を確認する。

# データベース生成
% rails db:migrate
# データベースクライアントの起動
% rails dbconsole
# テーブル構造の確認
sqlite> .schema
...
CREATE TABLE IF NOT EXISTS "users" ("id" integer PRIMARY KEY AUTOINCREMENT NOT NULL, "email" varchar DEFAULT '' NOT NULL, "encrypted_password" varchar DEFAULT '' NOT NULL, "reset_password_token" varchar, "reset_password_sent_at" datetime, "remember_created_at" datetime, "post_code" varchar, "address" varchar, "self_introduction" varchar, "created_at" datetime(6) NOT NULL, "updated_at" datetime(6) NOT NULL);
...
# データベースクライアントの終了
sqlite> .quit

Routes を確認するために、 http://localhost:3000/rails/info/routes をブラウザで見てみる。

image.png

アカウントの登録画面は、 http://localhost:3000/users/sign_in となっているので、ブラウザで確認する。

image.png

ビュー構成変更

ログイン画面等で属性の追加や I18n 対応をする場合、おそらく View が定義されていないといけない。ただ、 devise gem を導入した場合に用意されるページは、gem にパッケージ化されたを使用しているため、編集できない。

Devise で View をカスタマイズする場合は、config/initializers/devise.rb を編集する。下記のパラメータを設定することで、パッケージ化されたページではなく、用意したページを参照するようになる。

config.scoped_views = true

そして、ログインページ用の View ファイルを追加するために次のコマンドを実行する。

% rails generate devise:views users

実行すると、次のように View が作成される。

image.png

試しに、 app/views/users/sessions/new.html.erb を編集してみると、ちゃんと更新されるようになりました🤗

image.png

Strong Parameter設定

デフォルトのままだと、ユーザ情報で設定できる項目は、アドレスとパスワードになっている。他項目を追加できるようにしたい場合、 Strong Parameter を編集する。Strong Parametersを参考に進める。

Strong Parameter はコントローラにて設定する。簡単に設定する方法として、次のコードを app/controllers/application_controller.rb に追加する。

before_action :configure_permitted_parameters, if: :devise_controller?

protected

def configure_permitted_parameters
  devise_parameter_sanitizer.permit(:sign_up, keys: [:post_code, :address, :self_introduction])
  devise_parameter_sanitizer.permit(:account_update, keys: [:post_code, :address, :self_introduction])
end

devise_parameter_sanitizer.permit メソッドの第一引数は、アクションの種類で次の3種類で設定できる。

  • sign_in :セッション管理用
  • sign_up :ユーザ情報の新規登録用
  • account_update :ユーザ情報の更新用

上記のコードの場合、ユーザ情報の新規登録と更新について新しく属性を追加したいため、sign_up ,account_update を設定した。

そして、第二引数にて、追加したい属性を設定する。今回は郵便番号、住所、自己紹介を追加したいので、モデルに追加した属性( :post_code, :address, :self_introduction )を追加した。

上記までで、Viewでパラメータを扱えるようになったので、View(app/views/users/registrations/new.html.erb, app/views/users/registrations/edit.html.erb)に下記を追加する。

<div class="field">
  <%= f.label :post_code %><br />
  <%= f.text_field :post_code %>
</div>

<div class="field">
  <%= f.label :address %><br />
  <%= f.text_field :address %>
</div>

<div class="field">
  <%= f.label :self_introduction %><br />
  <%= f.text_area :self_introduction %>
</div>

下記のように追加したユーザ情報編集を編集できるようになりました🤗

image.png

ユーザ一覧ページの追加

ユーザ一覧を表示するために、コントローラとビューを生成する。(コントローラーとviewファイルの生成を参考にしました。)

% rails g controller Users index

上記コマンドを実行すると、config/routes.rbget 'users/index' が追加され、下記ファイルが生成される。

  • app/assets/stylesheets/users.scss
  • app/controllers/users_controller.rb
  • app/helpers/users_helper.rb
  • app/views/users/index.html.erb

cssとヘルパーは今回触らないので、一旦削除。

app/controllers/users_controller.rbapp/views/users/index.html.erbbook を参考に、それぞれ下記のように更新。

# app/controllers/users_controller.rb
class UsersController < ApplicationController
  before_action :authenticate_user!
  def index
    @users = User.order(:id).page(params[:page])
  end
end
<!-- app/views/users/index.html.erb -->
<p id="notice"><%= notice %></p>

<h1><%= User.model_name.human %></h1>

<table>
  <thead>
    <tr>
      <th><%= User.human_attribute_name(:email) %></th>
      <th><%= User.human_attribute_name(:post_code) %></th>
      <th><%= User.human_attribute_name(:address) %></th>
      <th><%= User.human_attribute_name(:self_introduction) %></th>
      <th colspan="3"></th>
    </tr>
  </thead>

  <tbody>
    <% @users.each do |user| %>
      <tr>
        <td><%= user.email %></td>
        <td><%= user.post_code %></td>
        <td><%= user.address %></td>
        <td><%= user.self_introduction %></td>
      </tr>
    <% end %>
  </tbody>
</table>

<%= paginate @users %>

そして、 http://localhost:3000/users/index にアクセスすると下記のように、ユーザ一覧が確認できるようになる✌️

image.png

ユーザ詳細ページの追加

詳細ページについても基本的にやる流れは同じ。

  • routes の編集

    URLをbooks と揃えるために、resources :books, :users を追加。

     # config/routes.rb
     resources :books, :users
    

    上記のように、resourcesを宣言するだけで、コントローラのindexshowneweditcreateupdatedestroyアクションの宣言が完了する。

    具体的には、次の7つのルーティングが対応付けされる。

    HTTP verb パス コントローラ#アクション 目的
    GET /users photos#index 一覧表示
    GET /users/new photos#new コンテンツ作成入力フォーム
    POST /users photos#create コンテンツ作成
    GET users/:id photos#show 特定コンテンツ表示
    GET users/:id/edit photos#edit 特定コンテンツ編集フォーム
    PATCH/PUT /users/:id photos#update 特定コンテンツ編集
    DELETE /users/:id photos#destroy 特定コンテンツ削除
  • controllers の編集

    URLからIDを取得するので、 controllers を次のように更新。

    # app/controllers/users_controller.rb  
    def show
     @user = User.find(params[:id])
    end
    
  • views の編集

    次のように更新。

    <!-- app/controllers/users_controller.rb  -->
    <p id="notice"><%= notice %></p>
    
    <h1><%= User.model_name.human %></h1>
    
    <table>
      <thead>
        <tr>
          <th><%= User.human_attribute_name(:email) %></th>
          <th><%= User.human_attribute_name(:post_code) %></th>
          <th><%= User.human_attribute_name(:address) %></th>
          <th><%= User.human_attribute_name(:self_introduction) %></th>
          <th colspan="3"></th>
        </tr>
      </thead>
    
      <tbody>
        <% @users.each do |user| %>
          <tr>
            <td><%= user.email %></td>
            <td><%= user.post_code %></td>
            <td><%= user.address %></td>
            <td><%= user.self_introduction %></td>
          </tr>
        <% end %>
      </tbody>
    </table>
    
    <%= paginate @users %>
    

これで、 http://localhost:3000/users/22 のようにアクセスすると、当該IDのユーザ情報が表示できるようになった🤗

image.png

参考