LoginSignup
0
0

More than 3 years have passed since last update.

Railsチュートリアル 第8章 基本的なログイン機構 - ログアウト

Posted at

ログアウト

前提条件

現在開発中のサンプルアプリケーションは、「ユーザーが明示的にログアウトするまではログイン状態を保つ」という仕様になっています。一方現状では、「ユーザーが明示的にログアウトする」という機能が実装されていません。

一方で、ログアウト機能の実装の前提となる以下の要素は既に実装済みです。

  • ログイン済みユーザー用ページの内容ヘッダー部における、ログアウト用のリンク
  • logout_pathへのDELETEリクエストに対する、sessions#destroyへのルーティング
  • Sessionsコントローラにおける、destroyアクションそのものの定義

これから新たに実装が必要になるのは、「Sessionsコントローラにおける、destroyアクションの実際の動作」ということになります。

session.deleteメソッド

セッションから情報を削除するために用いるメソッドです。今回削除するのはユーザーIDなので、引数として:user_idシンボルを取ります。

session.delete(:user_id)

上記コードを実行すると、指定したユーザーIDに対するセッションの情報をnilにできます。

Sessionsヘルパーにlog_outメソッドを実装する

ログアウト機能も、ログインに関連する機能と同様、様々なビューやコントローラで使われる可能性がある機能です。そのため、ログアウト機能の実体はSessionsヘルパーにlog_outメソッドとして実装していきます。

app/helpers/sessions_helper.rb
  module SessionsHelper

    ...略
+
+   # 現在のユーザーをログアウトする
+   def log_out
+     session.delete(:user_id)
+     @current_user = nil
+   end
  end

Sessionsコントローラのdestroyアクションを実装する

  class SessionsController < ApplicationController
    def new
    end

    def create
      user = User.find_by(email: params[:session][:email].downcase)
      if user && user.authenticate(params[:session][:password])
        log_in user
        redirect_to user
      else
        flash.now[:danger] = 'Invalid email/password combination'
        render 'new'
      end
    end

    def destroy
      log_out
      redirect_to root_url
    end
  end

ログアウト機能に対するテストを実装する

  require 'test_helper'

  class UsersLoginTest < ActionDispatch::IntegrationTest

    ...略

-   test "login with valid information" do
+   test "login with valid information followed by logout" do
      get login_path
      post login_path, params: { session: { email: @user.email, password: 'password' } }
      assert_redirected_to @user
      follow_redirect!
      assert_template 'users/show'
      assert_select "a[href=?]", login_path, count: 0
      assert_select "a[href=?]", logout_path
      assert_select "a[href=?]", user_path(@user)
+     delete logout_path
+     assert_not is_logged_in?
+     assert_redirected_to root_url
+     follow_redirect!
+     assert_select "a[href=?]", login_path
+     assert_select "a[href=?]", logout_path,      count: 0
+     assert_select "a[href=?]", user_path(@user), count: 0
    end
  end

テストの名前を変えた上で、以下の手順を追加しています。

  • logout_pathに対してdeleteアクションを実行する
  • logged_in?の戻り値がfalseになることを確認する
  • リダイレクト先がroot_urlであることを確認する
  • 実際にリダイレクト先へ移動する
  • ログインリンクが存在することを確認する
  • ログアウトリンクが存在しないことを確認する
  • ユーザープロフィールへのリンクが存在しないことを確認する

なんかテストの粒度が大きすぎる気もします…

ログアウト機能に対するテストを実行する

ここまでの実装で、テストは通るようになっているはずです。実際にテストを実行してみましょう。

# rails test                              
Running via Spring preloader in process 321
Started with run options --seed 31924

  24/24: [=================================] 100% Time: 00:00:02, Time: 00:00:02

Finished in 2.43459s
24 tests, 68 assertions, 0 failures, 0 errors, 0 skips

全体のテストが通りました。

  • ユーザー登録
  • ログイン
  • ログアウト

ここまでの実装が終わりましたね。

演習 - ログアウト

1. ブラウザから [Log out] リンクをクリックし、どんな変化が起こるか確認してみましょう。また、リスト 8.31で定義した3つのステップを実行してみて、うまく動いているかどうか確認してみましょう。

ログイン済みで、ログインユーザーのプロフィールページが表示された状態から開始します。

スクリーンショット 2019-11-03 22.14.04.png

「Log out」リンクをクリックします。rails serverのログには以下のログが記録されています。

Started DELETE "/logout" for 172.17.0.1 at 2019-11-03 13:14:29 +0000
Cannot render console from 172.17.0.1! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by SessionsController#destroy as HTML
  Parameters: {"authenticity_token"=>"v1pJUi79KnyRa8J1ocwc6k5iQcm2H1jLTBH+IiCqTDtq2ZoJSLJ3Bzh7sCy/C2GMy2vv6Sl6iUQC8oiA3VAT9Q=="}
Redirected to http://localhost:8080/
Completed 302 Found in 3ms (ActiveRecord: 0.0ms)

rails serverのログから、以下のことがわかります。

  • エンドポイント/logoutに対してDELETEリクエストが送出されている
  • Sessionsコントローラのdestroyアクションが実行されている
  • ルートのフルURLに対してリダイレクトされている
  • 最終的に戻ってきたHTTPステータスコードは302 Foundである

ルートのフルURLに対してGETリクエストが送出され、処理が200 OKで完了した後のブラウザのスクリーンショットは以下のようになります。

スクリーンショット 2019-11-03 22.14.38.png

「Log in」というリンクが内容のヘッダー部に表示されていますね。

2. cookiesの内容を調べてみて、ログアウト後にはsessionが正常に削除されていることを確認してみましょう。

スクリーンショット 2019-11-04 17.14.18.png

上記スクリーンショットは、Firefoxのストレージインスペクターによるログイン中のcookiesの内容です。

スクリーンショット 2019-11-04 17.14.43.png

続いてのスクリーンショットは、Firefoxのストレージインスペクターによるログアウト後のcookiesの内容です。cookiesの内容は変化していますが、sessionが削除されているかどうかは正直わかりません。一方で、ログイン中には表示されなかった「パース済みの値」というボックスが表示されるようになりました。

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