Ruby on Rails 5.2.1 上でdevise 4.5.0を利用する

目的

Ruby on Railsでよく使われている認証周りのgemライブラリーであるdeviseをつかってログイン機能を用いる。 deviseの標準ではemailに基づいてユーザを区別しているが、usernameでユーザを区別できるようにする。

環境

% lsb_release -a
No LSB modules are available.
Distributor ID:	Ubuntu
Description:	Ubuntu 18.04.1 LTS
Release:	18.04
Codename:	bionic

% ruby -v
ruby 2.5.1p57 (2018-03-29 revision 63029) [x86_64-linux]

% gem -v
2.7.7

% rails -v
Rails 5.2.1

新しいプロジェクトの生成

% rails new prac_devise --skip-bundle
% cd prac_devise
% cp -p Gemfile Gemfile.org
% vi Gemfile

Gemfileの中身を以下のように変更する。

% diff Gemfile.org Gemfile
17c17
< # gem 'mini_racer', platforms: :ruby
---
>  gem 'mini_racer', platforms: :ruby
62c62
< gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
---
> #gem 'tzinfo-data', platforms: [:mingw, :mswin, :x64_mingw, :jruby]
63a64
> gem 'devise'

bundleを実行する。

% bundle install --path vendor/bundle

ダミーモデルの作成

今回はHomeコントローラーを作成し、indexにアクセスする際にはログインなし、showにアクセスする場合はログインありに設定する。このためにHomeコントローラーを作成する。

% rails g controller Home index show

このアプリケーションのトップページをHome#indexとする。

% vi config/routes.rb 

中身に以下を加える。

root to: "home#index"

Deviseのインストール

このアプリケーションでdeviseが使えるように設定する。

% rails g devise:install

今回はUserモデルを認証対象のモデルとする。

% rails g devise User

devise用のviewを app/views/devise 以下にコピーする。

% rails g devise:views
% ls app/views/devise/
confirmations/	passwords/	sessions/  unlocks/
mailer/		registrations/	shared/

メールに記述するURLの設定

config/environments/development.rb に以下を加える。

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

エラーメッセージを表示できるようにする。

app/views/layouts/application.html.erbに以下を加える。

〜省略〜
  <body>
    <p class="notice"><%= notice %></p> #この行を追加
    <p class="alert"><%= alert %></p>        #この行を追加
    <%= yield %>
  </body>
〜省略〜

User#showへのアクセスをログインした場合のみにする

app/controllers/home_controller.rb にフィルターをかける。

class HomeController < ApplicationController

  before_action :authenticate_user!, only: :show #この行を追加

  def index
  end
〜省略〜

試してみる

% rails db:migrate
% rails s
(終了させるときは Ctrl + c)

識別キーをusernameに変更する

まず、usersテーブルにusernameを追加する。

% rails g migration add_username_to_users username:string

db/migrate/xxxxxxxxx_add_username_to_users.rb を編集し、usernameをインデックスとして使えるように以下を追加する。

class AddUsernameToUsers < ActiveRecord::Migration[5.2]
  def change
    add_column :users, :username, :string
    add_index :users, :username, unique: true #この行を追加
  end
end

上記の変更を反映させる。

% rails db:migrate

識別キーをusernameに変更する。 config/initializers/devise.rbに以下の行を加える。

〜 省略 〜
  # You can also supply a hash where the value is a boolean determining whether
  # or not authentication should be aborted when the value is not present.
  # config.authentication_keys = [:email]
  config.authentication_keys = [:username] #この行を追加
〜 省略 〜

ログイン(sign in)、ユーザ登録(sign up)、情報変更のページでusernameを入力できるように変更する。

ログインページ(app/views/devise/sessions/new.html.erb)の編集。

変更前
    <%= f.label :email %><br />
     <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
変更後
     <%= f.label :username %><br />
     <%= f.email_field :username, autofocus: true %>

ユーザ登録ページ(app/views/devise/registrations/new.html.erb) の編集。

変更前
     <%= f.label :email %><br />
     <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
変更後
     <%= f.label :username %><br />
     <%= f.text_field :username, autofocus: true %>

情報変更のページ(app/views/devise/registrations/edit.html.erb)の編集。

変更前
     <%= f.label :email %><br />
     <%= f.email_field :email, autofocus: true, autocomplete: "email" %>
変更後
     <%= f.label :username %><br />
     <%= f.text_field :username, autofocus: true %>

usernameにvalidateを設定およびemailを利用しないことを設定する。

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, :rememberable, :validatable

# この行以下を追加する

# usernameの制約
  validates :username,
            uniqueness: {case_sensitive: :false},
            length: {minimum: 4, maximum: 20},
            format: {with: /\A[a-z0-9]+\z/, message: "ユーザ名は半角英数字です"}

# emailを識別キーとして使わない場合の処理
  def email_required?
    false
  end

  def email_changed?
    false
  end
  
  def will_save_changed_to_email?
    false
  end
 
# 追加ここまで
end

strong_parameterの設定

Ruby on Rails4よりStrong Parameterという仕組みが導入されている。これの設定が必要。 app/controllers/application_controller.rb に以下を加える。

  # deviceのコントローラーのときに、下記のメソッドを呼ぶ
  before_action :configure_permitted_parameters, if: :devise_controller?

  protected
  
 # usernameを追加する 参考:https://github.com/plataformatec/devise#strong-parameters
  def configure_permitted_parameters
    devise_parameter_sanitizer.permit :sign_up, keys: [:usrname]
    devise_parameter_sanitizer.permit :account_update, keys: [:username]
  end

試してみる

% rails db:migrate
% rails s
(終了させるときは Ctrl + c)