deviseは、Webアプリケーションを作成する際にほぼ必ずと言っていいほど必要になる認証系の機能を網羅的に用意してくれるgemです。アカウントの登録やログイン、パスワードの再設定機能、アカウントロック機能等、豊富な機能が利用できます。各機能はモジュールに分解されているため、自分のアプリケーションに必要な機能だけを選んで導入することが可能になっています。
また、複数モデルの同時ログインにも対応しています。完全に影響を分割することができるので、管理ユーザーと一般ユーザーが1つのアプリに存在する場合でもそれぞれに異なる認証方式を導入することができます。
- 言語、ライブラリのバージョン
- 始める前に
- セットアップ
- deviseをmodelに適用する
- deviseでコントローラーをカスタマイズする(新規登録処理)
- deviseでコントローラーをカスタマイズする(ログアウト)
- ログインに伴う制御を行う
- まとめ
言語、ライブラリのバージョン
始める前に
erb→slimにする
erbを利用する方はここは読み飛ばしてしまって構いません。slimを使う方はここで設定をしておきましょう。
deviseがviewファイルを自動生成する際にslimで生成してほしいので、Gemfileに
gem 'slim-rails'
を記載し、$ bundle install
します。
これだけで今後viewファイル自動生成関係のコマンドではslimファイルが生成されます。
すでに存在するerbファイルをslimに変換する場合
生成済みのerbをslimに変換する場合、 html2slim
を使うと手っ取り早いです。ファイル数が少なければ手動でも対応可能ですが、gemとコマンドを利用すればファイル名の変換から中身の置換までを正確に行えるため導入しておきましょう。
gemのインストール
$ gem install html2slim
ファイルの変換
$ for i in app/views/**/*.erb; do erb2slim $i ${i%erb}slim && rm $i; done
セットアップ
まずはセットアップです。使用するためにはdeviseのgemをインストールしておく必要があります。Gemfileに追記をしましょう。
Gemfile
source 'https://rubygems.org' git_source(:github) { |repo| "https://github.com/#{repo}.git" } . . 中略 . . gem 'devise' #追記
下記コマンドを実行し、Gemfileの記載内容をもとにgemをインストールします。
$ bundle install
無事インストールできたらファイル生成のコマンドが利用できるようになっているはずなので、このコマンドを実行しましょう。
$ rails g devise:install
下記のような内容のログが表示されます。
create config/initializers/devise.rb create config/locales/devise.en.yml =============================================================================== 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. deviseの設定ファイル 2. deviseの英語用のlocaleファイル
です。また、セットアップ方法も出力されるのでそれに従って進めていきます。
1.デフォルトのurlオプションを設定する
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.
ここに書かれているように、deviseで使用するdefault_url_option
を設定します。メールの存在確認などで生成されるリンクのurlの基本設定です。
開発環境ではconfig/environments/development.rb
に
config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
と設定します。 本番環境では、hostの部分にアプリケーションのドメインを入力しましょう。
config/environments/produvtion.rb
config.action_mailer.default_url_options = { :host => ドメイン, :protocol => 'https'}
- トップページへアクセスしたときのルーティングを設定する
これは既存のアプリケーションなどにdeviseを導入する場合など、トップページにアクセスした場合のルーティングが設定されている場合はスキップしても構わないです。今回は作っていないのでroutes.rb
ファイルにコントローラーとルーティングを設定します。
homeコントローラーを作成
rails g controller home index
routes.rb
にroot to: 'home#index'
と記載
$ rails s
を行って http://localhost:3000 にアクセスした場合にこのようになればOKです。(変換前なのでerbになってます。)
- flash メッセージを表示するために、
views/layouts/application.html.slim
に追記します。
doctype html html head title | DeviseCommentaly = csrf_meta_tags = csp_meta_tag = stylesheet_link_tag ‘application’, media: ‘all’, ‘data-turbolinks-track’: ‘reload’ = javascript_pack_tag ‘application’, ‘data-turbolinks-track’: ‘reload’ body p.notice = notice #追記 p.alert = alert #追記 = yield
最後に、deviseのviewファイルをカスタマイズするために
$ rails g devise:views
コマンドを実行します。すると下記のviewファイルが作成されます。
app/views/devise/confirmations/new.html.slim app/views/devise/mailer/confirmation_instructions.html.slim app/views/devise/mailer/email_changed.html.slim app/views/devise/mailer/password_change.html.slim app/views/devise/mailer/reset_password_instructions.html.slim app/views/devise/mailer/unlock_instructions.html.slim app/views/devise/passwords/edit.html.slim app/views/devise/passwords/new.html.slim app/views/devise/registrations/edit.html.slim app/views/devise/registrations/new.html.slim app/views/devise/sessions/new.html.slim app/views/devise/shared/_error_messages.html.slim app/views/devise/shared/_links.html.slim app/views/devise/unlocks/new.html.slim
これらはパスワード再設定やメールアドレス変更のために利用します。
deviseをmodelに適用する
model新規作成の場合
deviseで制御するmodelを作成していきます。一般的に利用されるのはUserモデルだと思うので、今回はUserモデルを作成します。
$ rails g devise user
このコマンドでは以下の処理が実行されます
- devise用のmigrationファイル生成
- Userモデルのファイル生成
- routes.rbに、devise用のルーティングを定義する
devise_for :users
を追記
migrationファイルの中身はこのようになっています。
# frozen_string_literal: true class DeviseCreateUsers < ActiveRecord::Migration[6.0] def change create_table :users do |t| ## Database authenticatable t.string :email, null: false, default: "" t.string :name, null: false # 追加 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.inet :current_sign_in_ip # t.inet :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
コメントアウトされているいくつかの定義は冒頭で紹介したいくつかの機能を実現するために使用されるカラム群です。
今回は使用しないのでデフォルトのままでいきたいと思います。また、他のカラムをUserモデルに持たせたい場合はここに追記することもできます。今回はnameというカラムを追加して名前が登録できるようにしました。
なお、生成されたUserモデルはこのような内容です。
class User < ApplicationRecord # Include default devise modules. Others available are: # :confirmable, :lockable, :timeoutable, :trackable and :omniauthable devise :database_authenticatable, :registerable, :recoverable, :rememberable, :validatable end
バージョンによって多少の差はありますが、今回の構成だと
database_authenticatable #=> ログイン時に正当性を検証する機能。認証はPOSTリクエストかHTTPベーシック認証が使える registerable #=> 新規登録処理を実行しDBに保存する機能、またそのアカウントを編集、削除できるようにする機能 recoverable #=> パスワードのリセットを行い、変更手順を送る機能 rememberable #=> 保存されたCookieからユーザー情報を記憶するためのトークンを管理する機能 validatable #=> デフォルトでe-mailとパスワードの検証を提供する。optionであるためカスタマイズができる。
という機能がmodel生成時点で有効になっています。
続いてmigrationを行い、DBに定義を反映します。
$ rails db:migrate
これでdeviseコマンドで作成されたmigrationが反映されました。
ログイン画面がうまく表示されるか確認してみましょう。
$ rails s
でサーバーを起動し、/users/sign_up
にアクセスしてみます。
このように表示されていることが確認できれば成功です。
modelがすでに存在する場合
あまりないケースかもしれませんが、既にUserモデルが存在しており、そのモデルに対してdeviseを使用したい場合でも、
$ rails g devise user
このコマンドを実行することで適切なmigrationファイルが生成され、deviseの機能が使えるようになります。
ただし、既に同名のカラムが存在している場合はmigration実行時にエラーになりますので、重複している部分を削除してから実行を行ってください。
deviseでコントローラーをカスタマイズする(新規登録処理)
先ほどUserモデルにnameカラムを追加したのでdevise:views
で作成したファイルに、nameを入力できるようにフォームを改修します。
/app/views/devise/registrations/new.html.slim
h2 | Sign up = form_for(resource, as: resource_name, url: registration_path(resource_name)) do |f| = render "devise/shared/error_messages", resource: resource .field = f.label :name br = f.text_field :name .field = f.label :email br = f.email_field :email, autofocus: true, autocomplete: "email" .field = f.label :password - if @minimum_password_length em | ( = @minimum_password_length | characters minimum) br = f.password_field :password, autocomplete: "new-password" .field = f.label :password_confirmation br = f.password_field :password_confirmation, autocomplete: "new-password" .actions = f.submit "Sign up" = render "devise/shared/links"
ただ、このままだとsign_upの処理はdeviseのデフォルトのコントローラーが処理を行うため、独自に追加したnameというカラムはそのままでは保存できません。 このような場合はdeviseのコントローラーを上書きして、必要な処理を追加してあげる必要があります。今回はUserモデルに対してなので
$ rails g devise:controllers users
とターミナルに入力します。 出力されるログは以下。
create app/controllers/users/confirmations_controller.rb create app/controllers/users/passwords_controller.rb create app/controllers/users/registrations_controller.rb create app/controllers/users/sessions_controller.rb create app/controllers/users/unlocks_controller.rb create app/controllers/users/omniauth_callbacks_controller.rb =============================================================================== Some setup you must do manually if you haven't yet: Ensure you have overridden routes for generated controllers in your routes.rb. For example: Rails.application.routes.draw do devise_for :users, controllers: { sessions: 'users/sessions' } end ===============================================================================
このコマンドで新規登録やログインなどそれぞれの処理の際に呼ばれるコントローラーが生成されます。また、オーバーライドしたコントローラーにルーティングを渡したいので、例にあるようにroutes.rb
に
devise_for :users, controllers: { registrations: 'users/registrations' sessions: 'users/sessions' }
とルーティングを設定します。この記述によってusersにおける処理の行き先を指定しています。
ルーティングを指定し、コントローラーが自分の作成したものを経由するようになったらnameカラムを保存できるようにcontrollerに手を加えていきます。ちなみに自動生成されたusers/registrations_controller.rbは下記のようになっています。
# frozen_string_literal: true class Users::RegistrationsController < Devise::RegistrationsController # before_action :configure_sign_up_params, only: [:create] # before_action :configure_account_update_params, only: [:update] # GET /resource/sign_up # def new # super # end # POST /resource # def create # super # end # GET /resource/edit # def edit # super # end # PUT /resource # def update # super # end # DELETE /resource # def destroy # super # end # GET /resource/cancel # Forces the session data which is usually expired after sign # in to be expired now. This is useful if the user wants to # cancel oauth signing in/up in the middle of the process, # removing all OAuth session data. # def cancel # super # end # protected # If you have extra params to permit, append them to the sanitizer. # def configure_sign_up_params # devise_parameter_sanitizer.permit(:sign_up, keys: [:attribute]) # end # If you have extra params to permit, append them to the sanitizer. # def configure_account_update_params # devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) # end # The path used after sign up. # def after_sign_up_path_for(resource) # super(resource) # end # The path used after sign up for inactive accounts. # def after_inactive_sign_up_path_for(resource) # super(resource) # end end
このファイルの中の
before_action :configure_sign_up_params, only: [:create]
と
def configure_sign_up_params devise_parameter_sanitizer.permit(:account_update, keys: [:attribute]) end
のコメントアウトを外しておきます。
nameカラムに値を入れたいので、:attribute
となっている部分を下記のように:name
に変えます。複数ある場合はカンマ区切りで設定することができます。
devise_parameter_sanitizer.permit(:account_update, keys: [:name])
この部分を変更することによって任意の値を新規登録時に保存させることができます。
この段階ではconfirmableを有効にしていないので、新規登録が正常に実行されるとdeviseがログイン処理も行います。
ログイン後はデフォルトだとroot_path
にリダイレクトされるので、今回はHome#indexに遷移します。
deviseでコントローラーをカスタマイズする(ログアウト)
一連の動作を何度でも行えるように、ログアウト処理をつけておきましょう。 ログイン処理後に遷移するhome#indexにログアウト用のリンクをつけましょう。
h1 | Home#index p | Find me in app/views/home/index.html.slim = link_to 'ログアウト', destroy_user_session_path, method: :delete
これでボタンを押せばログアウトできるようになりました。
ログインに伴う制御を行う
現状までの状態で新規登録を行いそのままログイン、ログアウトまでの流れを実装できましたが、このような認証機能を入れたい理由の大半はログインしなければアクセスできないページが必要だからということが多いです。 今回はログインしていればアクセスすることができ、新規登録の際に登録したnameを表示するだけの簡単なmypageを作ってそれを検証してみます。
$ rails g controller mypage show
my page用のコントローラーを作成します。今回使用するのはshowメソッドにするので、showもこのタイミングで設定してしまいます。
routes.rbには自動でget 'mypage/show'
のようなメソッドが生成されているのでこのままアクセスできます。今回はそのままこのルーティングを使ってアクセスしていきます。
ではこのページに制御をかけていきます。
deviseを導入すると使えるようになるメソッドがいくつか提供されていて、その中で認証を行うためには
authenticate_user!
というメソッドを使用します。今回はbefore_actionを使用してmypageコントローラー全体に認証を設定します。
/app/controllers/mypages_controller.rb
class MypageController < ApplicationController before_action :authenticate_user! #追加 def show end end
これだけです。これでdeviseがログイン済みなのかどうか判定してくれます。この状態で先ほどの mypage/show
にアクセスしてみましょう。
ログアウトした状態でmypage/show
にアクセスするとログインページにリダイレクトされ、画像のようにデフォルトメッセージとして
You need to sign in or sign up before continuing.
と表示されます。
これでログインしているときにしか表示させないページという制御ができるようになったので、このページにログインしたユーザーの名前を表示していきます。
現在ログインしているユーザーを取得するにはdeviseをインストールすることで使えるようになったメソッドを使います。Userモデルに適用しているのでcurrent_user
というメソッドが利用できます。userという部分は適用するモデルによって変化するので、もしPersonというモデルに適用している場合であればcurrent_person
になります。
mypage/show.html.slimに下記のように記載します
/app/views/mypages/show.html.slim
h1 Mypage#show p Find me in app/views/mypage/show.html.slim //追加 = current_user.name
この状態でログインしてmypage/show
にアクセスしてみましょう。
今回の例ではnameには「test」という名前で登録をしているので、testとmypage/showに表示されれば成功です。
まとめ
deviseの導入から基本的な使い方を解説しました。deviseは色々なカスタマイズに対応できる作りとなっており、要件にあわせて適切に改修していくことが可能です。カスタマイズについては他の記事で解説をしていますので、興味があればdevise
タグから探してみてください。