0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Deviseの導入

Last updated at Posted at 2025-01-09

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する

.Gemfile
gem "devise"
.terminal
bundle install

②Deviseのセットアップ
下記コマンドを実行

.terminal
rails generate devise:install

下記ファイルが生成されます。
初期設定ファイル:config/initializers/devise.rb → Deviseのgemファイル
ロケールファイル:config/locales/devise.en.yml → Deviseの認証Gemで使用される国際化(i18n)対応の翻訳ファイル。エラーメッセージ、メールの件名、パスワードリセットの手順のメッセージなどの設定、カスタマイズができる。

Deviseの設定と確認

①Userモデルの作成

.terminal
rails generate devise User

下記が生成されます。
Userモデル(デフォルトでDeviseがサポートする機能が含まれます)
マイグレーションファイル(ユーザー認証に必要なカラムが含まれる)

②マイグレーションを実行

.terminal
rails db:migrate

③ルーティングの設定の確認
Userモデルを生成すると自動的にconfig/routes.rbに下記が記載されているので、記載があるか確認する。

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です。

image.png

※viewを編集したくなったら

.terminal
rails generate devise:views

をコマンド実行するとDeviseのビューファイルが作成されます。
自分の好きなデザインなどに変えたい方はこちらを実行してください。

ルートパスとなるページを作成する

非ログインしていないと新規投稿や編集ページなどにアクセスできないようし、アクセスするとルートパスにリダイレクトするように設定します。そのためルートパスとして簡単なページを作成していきます。

①rails g controller homes topを実行
コントローラーとアクションを作成します

.terminal
rails g controller homes top

②ルーティングを設定。
routes.rbに下記を記載することによってルートパスをhomes#topに設定する

routes.rb
root to: "homes#top"

③top.html.erbビューファイルを作成する
bootstrapのクラスを利用してルートパスとなるページを作成します。

top.html.erb
<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" %>

これでルートパスとなるページの作成と設定が完了しました。
画面は下記のようになります。
image.png

ログイン時と非ログイン時の動作設定

非ログイン時にindex,new,create,edit,update,destroyのアクションを操作できないように設定します。

①コントローラーにbefore_action :authenticate_user!を追加する

posts.controller.rb
before_action :authenticate_user!, only: [:index, :new, :create, :edit, :update, :destroy]

authenticate_user! はDeviseが提供するメソッド。コントローラーに追加すると、ログインしていないユーザーはそのアクションにアクセスできなくなります。←重要

②リダイレクト先の設定
ApplicationControllerにログイン、ログアウト後のリダイレクト先を指定する。

.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カラムを追加します
下記を実行します。

.terminal
rails g migration AddUserIdToPosts user:references
rails db:migrate

user:references を使用してuser_idカラムを作成し、PostがUserに紐づくように設定します。

次にposts_controller.rbのcreateアクションを修正

posts_controller.rb
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に下記を記載

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トークンが一致せず、エラーが起きている状態になります。このような状態は避けたいため、ブラウザのキャッシュを無効化することによって対応していきます。

⑤キャッシュの無効化
下記を記載

posts.controller.rb
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

上記のように記載することでキャッシュを使用しないように設定できます。

一旦終了します。

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?