【Rails】deviseを使った認証機能の実装【初学者】

はじめに

Railsアプリに認証機能を導入するには「devise」というGemを使う方法が最も簡単です。「devise」は認証に係る機能をほとんどコードを書くことなく実装できる反面、処理がブラックボックス化されており、全容が把握しづらいというデメリットがあります。Railsで初めて認証機能を導入する場合、まずは簡単な認証機能を自分で実装し、認証機能に関する理解を深めておくことをおすすめします。認証機能を自分で実装する方法については以下の記事を参照してください。

本記事では、「devise」を使った認証機能の実装について説明します。

「devise」の基本的な使い方

「devise」のインストール

「devise」をインストールするには、Gemfileに以下を追記し、bundle installを実行します。

Gemfile

gem 'devise'

次に、ターミナルで以下のコマンドを実行します。

$ rails generate devise:install

上記のコマンドを実行すると以下のファイルが作成されます。

ファイル 説明
config/initializers/devise.rb 「devise」の設定ファイル。
config/locales/devise.en.yml 「devise」の言語ファイル(英語)。

また、初めに行っておく必要のある設定などについて指示されるので、指示に従って設定を行います。

デフォルトURLの設定

「devise」では、ユーザー登録を行う際に入力したメールアドレスにメールを送り、本登録を完了させるという機能を追加することができます。その際、メールに記載するURLのドメイン名をあらかじめ設定しておく必要があります。

開発環境の場合、config/environments/ディレクトリ配下のdevelopment.rbファイルに以下を追記します。

development.rb

Rails.application.configure do
  # 以下を追記
  config.action_mailer.default_url_options = { host: 'localhost', port: 3000 }
end

本番環境の場合、config/environments/ディレクトリ配下のproduction.rbファイルに上記の開発環境と同じ設定に対し、ご自分のドメイン名とポートを設定します。以下は設定例です。

production.rb

Rails.application.configure do
  # 以下を追記
  config.action_mailer.default_url_options = { host: 'www.example.com', port: 80 }
end

ルートルーティングの設定

「devise」は、ユーザー登録の完了時やパスワードの変更後にデフォルトのリダイレクト先としてルートに遷移するようになっています。デフォルトのリダイレクト先を変更しない場合は、ルートのルーティングを設定しておく必要があります。

$ rails generate controller Statics index

routes.rb

Rails.application.routes.draw do
  # 以下を追記
  root 'statics#index'
end

デフォルトのリダイレクト先を変更するには、後述する「リダイレクト先の変更」セクションを参照してください。

フラッシュメッセージの表示

「devise」は、ログイン/ログアウト成功時などにフラッシュメッセージを設定します。必須ではありませんが、それらのフラッシュメッセージの表示を設定しておきます。以下はレイアウトにフラッシュメッセージを設定する例です。

application.html.erb

<!DOCTYPE html>
<html>
  <head>
    <title>RailsDevise</title>
    <meta name="viewport" content="width=device-width,initial-scale=1">
    <%= csrf_meta_tags %>
    <%= csp_meta_tag %>

    <%= stylesheet_link_tag 'application', media: 'all', 'data-turbolinks-track': 'reload' %>
    <%= javascript_pack_tag 'application', 'data-turbolinks-track': 'reload' %>
  </head>

  <body>
    <%# 以下を追記 %>
    <p class="notice"><%= notice %></p>
    <p class="alert"><%= alert %></p>
    <%= yield %>
  </body>
</html>

モデルの作成

「devise」で使用するモデルを作成します。モデル名は通常Userにしますが、これ以外のモデル名にすることもできます。

$ rails generate devise User

上記のコマンドを実行すると、モデルの作成、マイグレーションファイルの作成、ルーティングの追加などが行われます。モデルやマイグレーションには様々なオプションが用意されており、コメントアウトを外し有効にすることでオプションの機能を追加することができます。

モデルおよびマイグレーションの必要な機能を有効にしたら、以下のコマンドを実行します。

$ rails db:migrate

これで「devise」の基本的な機能を使用する準備ができました。

ヘルパーメソッド

「devise」にはコントローラーやビューで使用する様々なヘルパーメソッドが用意されています。なお、以下はモデル名をUserとした場合の例です。例えば、モデル名がMemberの場合、ヘルパーメソッドはauthenticate_member!のようになります。

ヘルパーメソッド 説明
authenticate_user! このヘルパーメソッドを設定したアクションが実行されるとき、ユーザーがログインしていなければログイン画面に遷移する。
user_signed_in? ユーザーがログインしているかどうかを判定する。
current_user 現在ログインしているユーザー情報を取得する。
user_session 現在ログインしているユーザーのセッションを取得する。

authenticate_user!の使い方は以下の通りです。

users_controller.rb

class UsersController < ApplicationController
  before_action :authenticate_user!, only: [:show, :edit, :update, :destroy]

  # アクションは省略
end

「devise」のカスタマイズ

「devise」の日本語化

「devise」で作成されたフォームやフラッシュメッセージを日本語化するには、config/ディレクトリ配下のapplication.rbに以下を追記します。

application.rb

module RailsDevise
  class Application < Rails::Application
    # 以下を追記
    config.i18n.default_locale = :ja
  end
end

次に、Gemfileに以下を追記しbundle installを実行します。

Gemfile

# 以下を追記
gem 'devise-i18n'

一部の文言だけ変更したい場合は、config/locale/ディレクトリ配下にdevise.ja.ymlファイルを作成し、変更したい文言とその訳を追記します。利用可能な文言は同ディレクトリ配下にあるdevise.en.ymlを参照してください。

devise.ja.yml

ja:
  devise:
    sessions:
      signed_in: "ログインに成功しました。"
      signed_out: "ログアウトに成功しました。"

ルーティングの変更

デフォルトのルーティングを変更したい場合、devise_forメソッドのオプションを使用します。

routes.rb

Rails.application.routes.draw do
  devise_for :users, path: 'auth', path_names: [sign_in: 'log_in']
end

上記のようにオプションを追加すると、ログイン画面のルーティングは/users/sign_inから/auth/log_inに変更されます。特定のルーティングを/sign_inのようにしたいなど、より詳細な変更が必要な場合、devise_scopeブロック内に通常のルーティングを記述します。

routes.rb

Rails.application.routes.draw do
  # 以下は残す
  devise_for :users

  # 以下を追記
  devise_scope :user do
    get '/sign_in', to: 'users/sessions#new'
  end
end

上記のように設定すると、/users/sign_inの他に/sign_inも使えるようになります。devise_forを削除してしまうと、devise_scopeブロック内のルーティング以外が使えなくなるのでご注意ください。

カスタムビューの作成

ユーザー登録画面やログイン画面を変更したい場合、カスタムビューを作成します。

$ rails generate devise:views users

上記のコマンドを実行すると、app/views/users/ディレクトリ配下に「devise」で使用するすべてのビューが作成されます。特定のビューのみ作成したい場合は-vオプションを使用します。

$ rails generate devise:views users -v sessions registrations

カスタムビューが存在しない場合はデフォルトのビューが使用されます。

カスタムコントローラーの作成

「devise」の処理を変更したい場合、カスタムコントローラーを作成します。

$ rails generate devise:controllers users

上記のコマンドを実行すると、app/controllers/usres/ディレクトリ配下に「devise」で使用するすべてのコントローラーが作成されます。特定のコントローラーのみ作成したい場合は-cオプションを使用します。

$ rails generate devise:controllers users -c sessions registrations

カスタムコントローラーやカスタムアクションが存在しない場合はデフォルトのコントローラーやアクションが使用されます。

作成したカスタムコントローラーを使用するようルーティングを変更します。

routes.rb

Rails.application.routes.draw do
  # 以下を修正
  devise_for :users, controllers: {
    sessions: 'users/sessions',
    registrations: 'users/registrations'
  }
end

ストロングパラメーターの追加

カスタムビューを作成し、ユーザー登録画面などのパラメーター(IDやパスワードなど)を追加する場合、ストロングパラメーターを追加する必要があります。ストロングパラメーターを追加するには、application_controller.rbに以下を追記します。

application_controller.rb

class ApplicationController < ActionController::Base
  # 以下を追記
  before_action :configure_sign_up_parameters, if: :devise_controller?

  protected
    def configure_sign_up_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:user_name])
    end
end

カスタムコントローラーに追加することもできます(カスタムコントローラーを作成している場合)。

registratioins_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  # 以下を追記
  before_action :configure_sign_up_parameters, only: [:create]

  protected
    def configure_sign_up_parameters
      devise_parameter_sanitizer.permit(:sign_up, keys: [:user_name])
    end
end

リダイレクト先の変更

ユーザー登録/解除、ログイン/ログアウトが成功したときのデフォルトの遷移先はルートです。これらのリダイレクト先を変更することができます。ユーザー登録/解除とログイン/ログアウトで変更方法が異なるので分けて説明します。

ユーザー登録/解除のリダイレクト先

以下のコマンドを実行して、「devise」のカスタムコントローラーを作成します。

$ rails generate devise:controllers users

app/controllers/users/ディレクトリ配下のregistrations_controller.rbを以下のように修正します。

registrations_controller.rb

class Users::RegistrationsController < Devise::RegistrationsController
  # 以下のコメントアウトを外す

  # The path used after sign up.
  def after_sign_up_path_for(resource)
    # 以下を修正
    user_path
  end

  # The path used after sign up for inactive accounts.
  def after_inactive_sign_up_path_for(resource)
    # 以下を修正
    new_user_registration_path
  end
end

次に、routes.rbを以下のように修正します。

routes.rb

Rails.application.routes.draw do
  # 以下を修正
  devise_for :users, controllers: {
    registrations: 'users/registrations'
  }
end

ログイン/ログアウトのリダイレクト先

application_controller.rbに以下を追記します。

application_controller.rb

class ApplicationController < ActionController::Base
  # 以下を追記

  def after_sign_in_path_for(resource)
    user_path
  end

  def after_sign_out_path_for(resource)
    new_user_session_path
  end
end

after_sign_in_path_forメソッドおよびafter_sign_out_path_forメソッドは「devise」で実装しているメソッドです。これらのメソッドをオーバーライドしています。

確認メール送信設定

ユーザー登録時に入力されたメールアドレスに確認メールを送信し、メールアドレスの認証を行う機能を追加します。なお、以下の手順は送信元メールにGmailを使用する場合の例です。

カラムの追加

確認メールで使用するカラムをテーブルに追加します。

yyyymmddhhmmss_devise_create_users.rb

class DeviseCreateUsers < ActiveRecord::Migration[6.1]
  def change
    create_table :users do |t|
      ... 

      ## Confirmable
      # 以下のコメントアウトを外す
      t.string   :confirmation_token
      t.datetime :confirmed_at
      t.datetime :confirmation_sent_at
      t.string   :unconfirmed_email # Only if using reconfirmable

      ...
    end
  end
end

テーブル作成後にカラムを追加したい場合、カラム追加のマイグレーションを作成します。

$ rails generate migration add_confirmable_to_users

yyyymmddhhmmss_add_confirmable_to_users.rb

class AddConfirmableToUser < ActiveRecord::Migration[6.1]
  def change
    # 以下を追記
    add_column :users, :confirmation_token, :string
    add_column :users, :confirmed_at, :datetime
    add_column :users, :confirmation_sent_at, :datetime
    add_column :users, :unconfirmed_email, :string
  end
end

マイグレーションが用意できたら以下を実行します。

$ rails db:migrate

モデルの変更

確認メールを送信する設定をモデルに追加します。

user.rb

class User < ApplicationRecord
  devise :database_authenticatable, :registerable,
         :recoverable, :rememberable, :validatable,
         # 以下を追記
         :confirmable
end

メール送信の設定

まず、メール送信設定で使用する機密情報をCredentialsに登録します。

$ EDITOR=vi rails credentials:edit

google:
  mail: YourMailAddress
  password: YourPassword

メールアドレスにGmailを使用する場合、アプリパスワードの設定が必要になります。アプリパスワードの設定については以下の記事の「アプリ パスワードを作成、使用する」セクションを参照してください。

config/initializers/ディレクトリ配下のdevise.rbを以下のように修正します。

devise.rb

Devise.setup do |config|
  # ==> Mailer Configuration
  # Configure the e-mail address which will be shown in Devise::Mailer,
  # note that it will be overwritten if you use your own mailer class
  # with default "from" parameter.
  # 以下を修正
  config.mailer_sender = Rails.application.credentials.google[:mail]
end

config/environments/ディレクトリ配下のdevelopment.rbに以下を追記します。

development.rb

Rails.application.configure do
  # 以下を追記
  config.action_mailer.raise_delivery_errors = true
  config.action_mailer.delivery_method = :smtp
  config.action_mailer.smtp_settings = {
    :address => "smtp.gmail.com",
    :port => 587,
    :user_name => Rails.application.credentials.google[:mail],
    :password => Rails.application.credentials.google[:password],
    :authentication => :plain,
    :enable_starttls_auto => true
  }
end

以上で確認メール送信設定は完了です。なお、確認メール送信設定を行う以前に登録していたアカウントについては、ログインする際にメールアドレスの確認が必要になっています。その場合は確認メールの再送信を行ってください。

まとめ

認証機能を導入するだけなら「devise」は最も簡単な方法のひとつです。しかし、実際には「devise」のデフォルトセットでは物足りないという場合が多く、いくつかの追加の機能を実装する必要が出てくるかもしれません。その際、一度認証機能を自分で実装しているとその経験がきっと役に立つはずです。

本記事を参考にして、「devise」を使って認証機能を実装していただければと思います。

関連記事

【Ruby】Bundlerを使ってRubyGemsを作成/公開する方法
# はじめに Bundlerを使ってRubyGemsを作成および公開する方法について説明します。Bundlerを使わずにRubyGemsを作成/公開する方法については以下の記事を参照してください。 <iframe class="hatena [...]
2022年7月12日 23:18
【Ruby】RubyGemsを作成/公開する方法
# はじめに RubyGemsを作成および公開する方法について説明します。Bundlerを使ってRubyGemsを作成する方法については以下の記事を参照してください。 <iframe class="hatenablogcard" style [...]
2022年7月11日 21:52
【Rails】M1チップ搭載MacでRuby on Railsの開発環境構築
# はじめに M1チップ搭載MacにRuby on Railsの開発環境を構築する手順を記載します。 - MacBook Air (M1, 2020) - macOS Monterey 12.3.1 # Homebrew ## [...]
2022年5月5日 11:56
【Rails】Rakeタスクの基本情報と作成・実行方法
# はじめに Railsには標準でRakeというGemが同梱されています。RakeはRubyで実装されたMake(UNIX系のOSで使用できるコマンド)のようなビルド作業を自動化するツールです。Ruby Make、略してRakeというわけですね。 [...]
2022年3月7日 22:12
【Rails】モデルに外部キーを設定する方法とよく起こるエラー内容について
# はじめに Railsでモデルに外部キーを設定する方法について説明します。 # モデルに外部キーを設定する ## リレーションシップ 今回は1つのブログ記事は複数のコメントを持つ1対多のリレーションシップを例に説明します。現在は` [...]
2022年2月10日 14:18
【Rails】Capybaraのfill_inメソッドを実行すると「既存レコードの内容+指定した内容」がセットされる事象の原因と対処【RSpec】
# はじめに RSpec + Capybaraを使用して、Railsアプリの統合テストを実装しています。とあるモデルの編集画面において、入力フォームの内容を書き換えた上で送信し、レコードが更新されることを確認します。 入力フォームの内容を書 [...]
2022年1月27日 21:22
【Rails】GitHubのセキュリティアラートで発見された脆弱性を解消する方法
# はじめに GitHubにはセキュリティアラートという機能があります。セキュリティアラートはリポジトリに含まれるライブラリやパッケージの脆弱性を定期的にチェックし、脆弱性のあるライブラリやパッケージが発見されたらアラートで知らせてくれるという機 [...]
2022年1月16日 10:36
【Rails】devise-two-factorを使った2段階認証の実装方法【初学者】
# はじめに Railsアプリで2段階認証を実装するには、「rotp」というGemを使う方法の他に、「devise-two-factor」というGemを使う方法があります。「devise-two-factor」はその名の通り、IDとパスワードによ [...]
2021年12月12日 17:58