Deviseによる認証機能 (解説編)
Devise とは?
Devise は、Rails でユーザー認証機能を高速かつ安全に実装できる認証ライブラリです。
以下のような機能をまとめて提供します。
Devise でできること(機能モジュール)
Devise は、複数の 「機能モジュール」 を組み合わせて
ユーザー認証を構成します。
User モデルにモジュールを指定するだけで、
必要な機能を段階的に追加できます。
① database_authenticatable(必須)
-
パスワードでログインする基本機能
-
パスワードを安全なハッシュ(BCrypt)に変換して保存
-
email + password によるログイン
-
誤入力時のエラー制御
-
認証チェック用 authenticate_user!
ほぼすべての Devise アプリで使われるユーザー認証の中核となるモジュールです。
② registerable
-
ユーザー登録(サインアップ)関連の機能
-
新規登録フォーム
-
登録後の自動ログイン
-
登録情報の編集(メール / パスワード / 任意項目)
-
アカウント削除(退会)
ユーザー自身がアカウントを管理できるようになります。
③ recoverable
-
パスワード再設定(リセット)機能
-
「パスワードを忘れた場合」リンク
-
再設定用メール送信
-
トークンによる本人確認
-
新しいパスワード設定
メール経由で安全にパスワードを変更できるため、実サービスではほぼ必須の機能です。
④ rememberable
-
ログイン状態の保持(Remember me)
-
Cookie にログイン情報を保存
-
次回アクセス時に自動ログイン
ログインフォームに 「次回から自動ログイン」 チェックを付けたい場合に利用します。
⑤ validatable
-
メール・パスワードのバリデーションを自動適用
-
メール形式チェック
-
メールの一意性(重複禁止)
-
パスワードの最小文字数(6文字以上)
-
確認用パスワードとの一致チェック
モデルにバリデーションを自前で書かなくてよいのが大きなメリットです。
⑥ confirmable
-
メール認証(本登録)機能
-
登録時に確認メールを送信
-
メール内 URL をクリックするまでログイン不可
-
確認メールの再送信が可能
サービスとして本格的に公開する場合は導入が推奨されます。
⑦ lockable
-
ログイン失敗回数によるアカウントロック
-
一定回数ログイン失敗でロック
-
時間経過による自動解除
-
管理者による解除も可能
不正ログイン対策として有効です。
⑧ timeoutable
- 一定時間操作がなければ自動ログアウト
例:30分操作なし → 自動ログアウト
セキュリティレベルを高めたい場合に有効です。
⑨ trackable(使用頻度は低め?)
-
ログイン履歴の記録
-
最終ログイン日時
-
IP アドレス
-
ログイン回数
近年はプライバシー配慮の観点から、
あえて使用しないケースも増えているとか?
Devise が提供するビュー(画面)
Devise は内部に認証用ビューを持っており、
必要に応じて アプリ側にコピーしてカスタマイズできます。
docker compose exec web bin/rails g devise:views
主に提供される画面:
-
ログイン(sessions/new)
-
新規登録(registrations/new)
-
登録情報編集(registrations/edit)
-
パスワード再設定(passwords/new, edit)
-
メール認証(confirmations)
-
ロック解除(unlocks)
-
OAuth 連携(omniauth)
デザインは自由に変更可能で、
CSS フレームワーク(Tailwind など)とも問題なく併用できます。
Devise の便利メソッド
Devise は Rails 全体で使える認証関連のヘルパーメソッドを提供します。
メソッド内容
current_user 現在ログイン中のユーザー
user_signed_in? ログインしているか
authenticate_user! 未ログイン時にアクセス制限
sign_in(user) 指定ユーザーでログイン
sign_out(:user) ログアウト
ゲストログインなどもsign_in を使って実装できます。
Deviseによる認証機能 (実装編)
(トップページのみ公開・それ以外はログイン必須)
前半では Devise の概要とモジュール構成を解説しました。
ここからは 実際の実装手順 をコード付きでまとめます。
1. Devise の導入
まずはGemfileに以下を記入し、反映させます。
gem "devise"
docker compose exec web bundle install
DeviseをRailsアプリで使うための初期設定をします。
docker compose exec web rails g devise:install
config/initializers/devise.rbが生成されます。
2. User モデル作成
モデルを作成し、反映させます。
docker compose exec web rails g devise User nickname:string
docker compose exec web rails db:migrate
※ nicknameは任意です。
3. Devise 初期設定(開発環境)
パスワード再設定メールなどで使用される URL の設定です。
config/environments/development.rb
config.action_mailer.default_url_options = { host: "localhost", port: 3000 }
4. 認証の基本設計
ApplicationController
全ページをログイン必須にし、Devise 関連のみ例外化します。
class ApplicationController < ActionController::Base
before_action :authenticate_user!, unless: :devise_controller?
before_action :configure_permitted_parameters, if: :devise_controller?
protected
# ログイン後の遷移先(見ていたページが無ければ、HOME画面に遷移)
def after_sign_in_path_for(resource)
stored_location_for(resource) || home_path
end
# ログアウト後はタイトル画面に遷移
def after_sign_out_path_for(resource)
root_path
end
# ログイン不要の公開ページを許可する
def devise_controller_or_public_page?
devise_controller? || public_page?
end
# タイトルページを公開ページとして許可
def public_page?
controller_name == "pages" && action_name == "title"
end
# nicknameを許可
def configure_permitted_parameters
devise_parameter_sanitizer.permit(:sign_up, keys: [:nickname])
devise_parameter_sanitizer.permit(:account_update, keys: [:nickname])
end
end
この設計のポイント
-
ログイン必須ルールを1箇所に集約
-
公開ページだけを個別に例外指定できる
-
遷移制御も一元管理できる
5. 公開ページ(ログイン不要ページ)の設定
PagesController
トップページのみログイン不要にします。
class PagesController < ApplicationController
skip_before_action :authenticate_user!, only: [:index]
def index; end
end
6. ルーティング設定
config/routes.rb
Rails.application.routes.draw do
root "pages#index"
devise_for :users, controllers: {
registrations: "users/registrations",
sessions: "users/sessions"
}
# ↓ここからはそれぞれの内容です。
get "home", to: "home#index", as: :home
resources :products
resources :shops
resources :records
resources :categories, only: [:index, :create, :destroy]
resource :profile, only: [:show, :edit, :update]
end
結果
-
/(トップページ) → ログイン不要
-
それ以外 → ログイン必須
という構成になります。
7. ログイン・ログアウト後の遷移
すでに ApplicationController で定義済みです。
ログイン成功後 → home_path
ログアウト後 → root_path
ここもそれぞれで調整してください。
8. フラッシュメッセージのカスタマイズ
Devise のコントローラをオーバーライドして成功時のメッセージのみ変更します。
新規登録時
class Users::RegistrationsController < Devise::RegistrationsController
def create
super
end
end
ログイン時
class Users::SessionsController < Devise::SessionsController
def create
super do |resource|
resource.update_tracked_fields!(request) # ログイン履歴更新
flash.delete(:notice)
flash[:notice] = "お帰りなさい、#{resource.nickname}さん!".html_safe
end
end
end
※ 失敗時の挙動は Devise 標準のまま利用しています。
※ 「ログイン時」はオリジナル文に変更しています。不要であればデフォルト文のある
「新規登録時」と同じような記載でいいかと思います。
※ ログイン前はユーザー情報が無いのでresourseを使います。
9. ビュー(最小構成サンプル)
Qiita 用に CSS を極力省いた例 を載せます。
新規登録フォーム
<h2>新規登録</h2>
<%= form_for(resource, as: resource_name,
url: registration_path(resource_name)) do |f| %>
<%= render "shared/error_message", resource: resource %>
<div>
<%= f.label :nickname %><br>
<%= f.text_field :nickname %>
</div>
<div>
<%= f.label :email %><br>
<%= f.email_field :email %>
</div>
<div>
<%= f.label :password %><br>
<%= f.password_field :password %>
</div>
<div>
<%= f.label :password_confirmation %><br>
<%= f.password_field :password_confirmation %>
</div>
<%= f.submit "登録する" %>
<% end %>
※ 実際のプロジェクトではTailwind / Bootstrap などで装飾してください。
10. 公開トップページ例
app/views/pages/index.html.erb
<h1>App名</h1>
<%= link_to "ログイン", new_user_session_path %>
<%= link_to "新規登録", new_user_registration_path %>
まとめ
-
認証ルールは ApplicationController に集約する
-
公開ページは skip_before_action で明示的に例外化
-
ログイン / ログアウト後の遷移は Devise のフックを活用
-
フラッシュメッセージは必要な部分だけオーバーライド
この構成により、
「トップページだけ公開・それ以外はログイン必須」という設計をシンプルに実現できます。