Action Cableの習作: Examplesの更新: 2: ユーザの認証

今回は、ユーザの認証です。

1. モデルの作成
2. ユーザの認証
3. メッセージとコメントの表示
4. Action Cableの利用

ユーザの認証

Action Cable Examplesとの差異:
cookies.signedをcookies.encryptedに変更しました。

・ページの閲覧にはユーザの認証が必要。下記の要領でユーザを認証する。
・localhost:3000/session/newでユーザ名一覧を表示する。
・クリックしたユーザを認証する。
・認証後、localhost:3000/examplesを表示する。

Generate Sessions controller
ユーザ認証に用いるセッションコントローラを生成します。

bin/rails g controller Sessions new

Add session to routes
セッションをルーティングに追加します。
追加するリソースは単数でnewとcreateに限定します。

config/routes.rb

Rails.application.routes.draw do
  resource :session, only: %i[new create]
end 

ルーティングを確認します。

bin/rails routes

生成したページを確認します。

bin/rails s
open localhost:3000/session/new

Show User.all in sessions#new
sessions#newでユーザ名の一覧を表示します。

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  def new
    @users = User.all
  end

app/views/sessions/new.html.erb

<h1>Authenticate as one of the following users</h1>

<ul>
  <% @users.each do |user| %>
    <li><%= link_to user.name, session_url(user_id: user.id), method: :post %></li>
  <% end %>
</ul>

bin/rails s
open localhost:3000/session/new

Add Authentication concern
認証に用いるAuthentication concernを追加します。
上記をApplicationControllerにincludeします。

touch app/controllers/concerns/authentication.rb
app/controllers/concerns/authentication.rb

module Authentication
  extend ActiveSupport::Concern

  private
    def authenticate_user(user_id)
      if authenticated_user = User.find_by(id: user_id)
        cookies.encrypted[:user_id] ||= user_id
        @current_user = authenticated_user
      else
        @current_user = nil
        cookies.delete(:user_id)
        nil
      end
    end
end

app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  include Authentication
end

bin/rails s
open localhost:3000/session/new

Call authenticate_user in sessions#create
セッション生成時、authenticate_userを呼び出しユーザを認証します。

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  # ...
  def create
    authenticate_user(params[:user_id])
    redirect_to examples_url
  end

ユーザ認証後、examplesページは存在しないため下記のエラーが表示されます。

bin/rails s
open localhost:3000/session/new
=> NameError in SessionsController#create
undefined local variable or method `examples_url' for ...

Railsが表示するウェブブラウザのエラーコンソールで、@current_userとクッキーの中身を確認します。

@current_user
=> #<User id: 1, name: ...
>> cookies.encrypted[:user_id]
=> "1"

Generate Examples controller
認証後に用いるExamplesコントローラを生成します。

bin/rails g controller Examples index

Add examples to routes
Examplesをルーティングに追加します。
追加するリソースは複数でindexに限定します。

config/routes.rb

Rails.application.routes.draw do
  resource :session, only: %i[new create]
  resources :examples, only: :index

  root 'examples#index'
end

bin/rails routes -c examples

認証後に生成したページが表示されることを確認します。

bin/rails s
open localhost:3000

Add ensure_authenticated_user
セッションコントローラを除いて、ユーザ認証を求めるようにします。
ユーザが未認証であれば、認証ページにリダイレクトします。

app/controllers/concerns/authentication.rb

module Authentication
  extend ActiveSupport::Concern
 
  included do
    before_action :ensure_authenticated_user
  end

  private

    def ensure_authenticated_user
      authenticate_user(cookies.encrypted[:user_id]) || redirect_to(new_session_url)
    end

    def authenticate_user(user_id)
      # ...

app/controllers/sessions_controller.rb

class SessionsController < ApplicationController
  skip_before_action :ensure_authenticated_user, only: %i[new create]

ユーザが未認証/認証済で、意図通りに動くことを確認します。

bin/rails s
open localhost:3000

Show current_user.name in examples#index
現在認証されているユーザの名前をexamples#indexに表示します。
ログアウト用のリンクを用意します。

app/views/examples/index.html.erb

<h1>Action Cable Examples</h1>

<p>
  Hello <%= @current_user.name %>
  (<%= link_to 'Logout', session_path, method: :delete %>)!
</p>

ユーザ名を確認します。

bin/rails s
open localhost:3000

Add destroy to session routes
ログアウト用のルーティングを追加します。

config/routes.rb

  resource :session, only: %i[new create destroy]

bin/rails routes -c session

Call unauthenticate_user in sessions#destroy
sessions#destroyでユーザを未認証にします。

app/controllers/concerns/authentication.rb

    def unauthenticate_user
      @current_user = nil
      cookies.delete(:user_id)
    end

app/controllers/sessions_controller.rb

  def destroy
    unauthenticate_user
    redirect_to new_session_url
  end

ログイン/ログアウトできることを確認します。
bin/rails s
open localhost:3000

ユーザ認証は、以上になります。

この記事が気に入ったらサポートをしてみませんか?