Ruby on Railsのバージョン:7.2.1
Rubyのバージョン:3.3.5
Bootstrapの導入と適用をした後の続きです。
Deviseを使用して、認証機能を追加していきます。
Deviseとは?
1.ユーザーの新規登録(サインアップ機能)
2.ログイン、ログアウト
3.パスワードのリセット
4.メールアドレスの確認(ユーザーの新規登録時にメールを送って認証用のリンクを踏ませてアカウントの有効化を行う)など
Deviseをインストール、セットアップ(rails generate devise:install)、モデル生成、マイグレーションまで行うと上記機能が簡単に実装できます。非常に便利です。
Deviseの導入
①Gemのインストール
下記をGemfileに記載し、bundle installする
gem "devise"
bundle install
②Deviseのセットアップ
下記コマンドを実行
rails generate devise:install
下記ファイルが生成されます。
初期設定ファイル:config/initializers/devise.rb → Deviseのgemファイル
ロケールファイル:config/locales/devise.en.yml → Deviseの認証Gemで使用される国際化(i18n)対応の翻訳ファイル。エラーメッセージ、メールの件名、パスワードリセットの手順のメッセージなどの設定、カスタマイズができる。
Deviseの設定と確認
①Userモデルの作成
rails generate devise User
下記が生成されます。
Userモデル(デフォルトでDeviseがサポートする機能が含まれます)
マイグレーションファイル(ユーザー認証に必要なカラムが含まれる)
②マイグレーションを実行
rails db:migrate
③ルーティングの設定の確認
Userモデルを生成すると自動的にconfig/routes.rbに下記が記載されているので、記載があるか確認する。
devise_for :users
rails routes -g user
Prefix Verb URI Pattern Controller#Action
new_user_session GET /users/sign_in(.:format) devise/sessions#new
user_session POST /users/sign_in(.:format) devise/sessions#create
destroy_user_session DELETE /users/sign_out(.:format) devise/sessions#destroy
new_user_password GET /users/password/new(.:format) devise/passwords#new
edit_user_password GET /users/password/edit(.:format) devise/passwords#edit
user_password PATCH /users/password(.:format) devise/passwords#update
PUT /users/password(.:format) devise/passwords#update
POST /users/password(.:format) devise/passwords#create
cancel_user_registration GET /users/cancel(.:format) devise/registrations#cancel
new_user_registration GET /users/sign_up(.:format) devise/registrations#new
edit_user_registration GET /users/edit(.:format) devise/registrations#edit
user_registration PATCH /users(.:format) devise/registrations#update
PUT /users(.:format) devise/registrations#update
DELETE /users(.:format) devise/registrations#destroy
POST /users(.:format) devise/registrations#create
ここまでできれば基本的なDeviseの機能は使える状態になっていると思います。
試しに、サーバーを立ち上げてhttp://localhost:3000/users/sign_in に飛んでみましょう!
下記のようなページが表示されればOKです。
※viewを編集したくなったら
rails generate devise:views
をコマンド実行するとDeviseのビューファイルが作成されます。
自分の好きなデザインなどに変えたい方はこちらを実行してください。
ルートパスとなるページを作成する
非ログインしていないと新規投稿や編集ページなどにアクセスできないようし、アクセスするとルートパスにリダイレクトするように設定します。そのためルートパスとして簡単なページを作成していきます。
①rails g controller homes topを実行
コントローラーとアクションを作成します
rails g controller homes top
②ルーティングを設定。
routes.rbに下記を記載することによってルートパスをhomes#topに設定する
root to: "homes#top"
③top.html.erbビューファイルを作成する
bootstrapのクラスを利用してルートパスとなるページを作成します。
<h1>Homes#top</h1>
<%= link_to "サインイン", new_user_session_path, class: "btn btn-primary" %>
<%= link_to "サインアップ", new_user_registration_path, class: "btn btn-primary" %>
<%= link_to "投稿一覧", posts_path, class: "btn btn-primary" %>
これでルートパスとなるページの作成と設定が完了しました。
画面は下記のようになります。
ログイン時と非ログイン時の動作設定
非ログイン時にindex,new,create,edit,update,destroyのアクションを操作できないように設定します。
①コントローラーにbefore_action :authenticate_user!を追加する
before_action :authenticate_user!, only: [:index, :new, :create, :edit, :update, :destroy]
authenticate_user! はDeviseが提供するメソッド。コントローラーに追加すると、ログインしていないユーザーはそのアクションにアクセスできなくなります。←重要
②リダイレクト先の設定
ApplicationControllerにログイン、ログアウト後のリダイレクト先を指定する。
def after_sign_in_path_for(resource)
posts_path # ログイン後に投稿一覧ページにリダイレクト
end
def after_sign_out_path_for(resource_or_scope)
root_path # ログアウト後にホームページにリダイレクト
end
after_sign_in_path_for
after_sign_out_path_for
はDeviseの全体的な挙動を制御するコールバックメソッドと呼ばれるものです。
カスタマイズすることによってリダイレクト先を任意のURLやパスへ変更できます。
通常のアクション(createなど)
ユーザーからの直接的なリクエスト(例: フォーム送信)によって動作する。
明確なリクエスト(HTTPメソッドとエンドポイント)に基づく。
コールバックメソッド(after_sign_in_path_forなど)
Deviseがログイン/ログアウトの処理を行った後、内部的に自動的に呼び出される。
ユーザーが直接的にこれらのメソッドをリクエストするわけではない。
これでログイン時に投稿一覧ページへ、ログアウト時にホームパス(Homes#top)にリダイレクトします。
③ログインしているユーザーのみが投稿できるようにする
UserモデルとPostモデルのアソシエーション設定する
class User < ApplicationRecord
has_many :posts, dependent: :destroy
end
class Post < ApplicationRecord
belongs_to :user
end
これにより、current_user.postsが利用可能になります。
次にpostsテーブルにuser_idカラムを追加します
下記を実行します。
rails g migration AddUserIdToPosts user:references
rails db:migrate
user:references を使用してuser_idカラムを作成し、PostがUserに紐づくように設定します。
次にposts_controller.rbのcreateアクションを修正
def create
@post = current_user.posts.build(user_params)
if @post.save
redirect_to posts_path, notice: "投稿を作成しました"
else
render :new, status: :unprocessable_entity
end
end
current_user.posts.build(user_params) でログイン中のユーザーが作成した投稿を紐付けます。
④非ログイン時に編集、投稿削除ができないように設定する
posts.controller.rbに下記を記載
before_action :correct_user, only: [:edit, :update, :destroy]
~
~
private
def correct_user
unless @post.user == current_user
redirect_to posts_path, alert: "他のユーザーの投稿を編集または削除することはできません。"
end
end
correct_userはアクセス制御するためのメソッドです。
current_user はDeviseが提供するメソッドで、ログイン中のユーザーを取得します
before_action :correct_user, only: [:edit, :update, :destroy]と記載することによって、非ログインユーザはposts_pathにリダイレクトするようなりました。
以上で大丈夫かと思ったのですが、ログアウトした後に戻るボタンを押して削除ボタンを押したりするとActionController::InvalidAuthenticityToken in PostsController#destroyとエラーが出ます。
これはログアウトしたことによってセッションが無効化されているため、CSRFトークンが一致せず、エラーが起きている状態になります。このような状態は避けたいため、ブラウザのキャッシュを無効化することによって対応していきます。
⑤キャッシュの無効化
下記を記載
before_action :set_cache_buster
~
~
private
def set_cache_buster
response.headers["Cache-Control"] = "no-cache, no-store, max-age=0, must-revalidate"
response.headers["Pragma"] = "no-cache"
response.headers["Expires"] = "Fri, 01 Jan 1990 00:00:00 GMT"
end
上記のように記載することでキャッシュを使用しないように設定できます。
一旦終了します。