Railsチュートリアル9章攻略の第一歩を踏み出したい！【Remember meチェックボックス編】

##はじめに
Railsチュートリアル９章の内容について、少しでも理解の助けになるよう簡単にまとめてみました。
【[セッション永続化編](https://qiita.com/kurawo___D/items/18807bdce09c760f976b)】に引き続き今回は、【Remember meチェックボックス】についてまとめていきます！
<br>
##こんな方に読んで欲しい
Railsチュートリアルにてログイン機能を実装しており、尚且つ9章を終えたが理解度があまり足りていないかもと感じている方。
あと私自身。
<br>
##内容
セッション永続化を、ユーザーが自由に選択できるようにするためのチェックボックス機能の実装。

内容のほとんどを箇条書きでまとめてあります。
キリの良いポイントまで一旦まとめてから、コードの記述を行っています。

演習に関しては割愛してます。
<br>
##実装手順
__1.Remember meチェックボックスの実装__
__2.Remember meチェックボックスをテスト__
__3.Remember me機能自体のテスト__

<br>
##1.Remember meチェックボックスの実装
ユーザー自信がセッションの永続化を、自由に選択できるように、チェックボックス実装していきます。
<br>
####1-1.ログインフォームにチェックボックスを追加する。
　　●check_boxヘルパーメソッドでチェックボックスを作成。

　　　　➡︎labelメソッドに「:remember_me」として、チェックボックスと紐付け。

　　　　➡︎チェックボックスヘルパーメソッドの引数も「:remember_me」とする。

　　　　➡︎リクエストで送信した際:remember_meがsessionの値となる。
<br>
####1-2.セッション永続化をユーザーによる選択式にする。
　　●チェックボックスが、オンかオフかでセッションを永続にするかどうかを切り替えられるようにする。

　　●フォームからparamsで送られてくる、チェックボックスの値を使って切替を行う機能を実装する。

　　　　➡︎params[:session][:remember_me]として、ハッシュで送られてくる。

　　　　➡︎オンの時は、remember_meの値が'1'となり、オフの時は'0'となる。

　　　　　　→paramsの値が'1'ならユーザーを記憶する処理。

　　　　　　→'0'ならユーザーを忘れる処理を記述する。

　　　　➡︎以上を踏まえ、条件式を記述していく。

　　　　　　→条件分岐でも書けるが、三項演算子を使うと簡潔に記述できる。

　　　　　　→__params[:session][:remember_me] == '1' ?remember(user) : forget(user)__とする。

　　　　　　→:remember_meの値が'1'なら、渡されたユーザーを記憶し、'1'でないならユーザーを忘れる。

　　　　➡︎createアクションに上記のコードを記述することで、チェックボックスの処理が行われる。
<br>


>```ruby:sessions/new.html.erb
  #1-1
  <%= form_for(:session, url:login_path) do |f| %>
　
      <%= f.label :email %>
      <%= f.email_field :email %>
　
      <%= f.label :password %>
      <%= f.password_field :password%>
　
      <%= f.label :remember_me %> #チェックボックス追加。
      <%= f.check_box :remember_me %>
　
      <%= f.submit "ログイン"%>
　
  <% end %>
```

>```ruby:controllers/sessions_controller.rb
  #1-2
  def create
    user = User.find_by(email: params[:session][:email].downcase)
    if user && user.authenticate(params[:session][:password])
      log_in user
      #セッション永続化をユーザーによる選択式にする。
      params[:session][:remember_me] == '1' ? remember(user) : forget(user)
      redirect_to user
    else
      flash.now[:danger] = "失敗"
      render 'new'
    end
  end
```

<br>


##2.Remember meチェックボックスをテストする。
<br>

####1-1.テストユーザーにログインさせる。
　　●チェックボックスのテストをするためには、ユーザーをテスト上でログインさせる必要がある。

　　●そのために、テスト内でユーザーがログインできるようにするためのメソッドを定義する。
　　　　➡︎コントローラの単体テストを利用。

　　　　➡︎test_helperファイル内の、ActiveSupport::TestCaseクラス内に定義する。

　　　　　　→log_in_as(user)ヘルパーメソッドを定義する。

　　　　　　→session[:user_id] = user.idとして、セッションメソッドを使い、テストユーザーとして直接ログインさせる処理を記述。

　　　　➡︎統合テスト用にも、同様のヘルパーメソッド(log_in_as)を実装する。

　　　　➡︎test_helperファイル内に、ActionDispatch::IntegrationTestクラスを新たに記述し、その中に定義する。

　　　　　　→ただし、__統合テストではsessionを直接扱うことはできない。__

　　　　　　→__Sessionsリソースに対し、postを送信することでログインさせる。__

　　　　　　→メソッド名はlog_in_asとして、単体テストのメソッド名と合わせる。合わせることで、共同で開発する際に「ユーザーのログイン」をテストする場合は「log_in_asメソッド」を呼べばいいというシンプルな認識にできる。

　　　　　　→メソッドの引数に、ログインに有効な値をデフォルト値を記述しておくと便利。
<br>
####1-2.remember meチェックボックスの動作を確認するためのテストを2つ。
　　●1-1の統合テストで定義したlog_in_asメソッドを利用する。

　　●1つ目：チェックボックスをオンとした場合。

　　　　➡︎単純に、__テストユーザーがチェックボックスをオン、すなわちremember_meの値を'1'として、ログインする場合を検証__すればいい。

　　　　　　→log_in_as(＠user,remember_me: '1')

　　　　　　→第二引数は、ヘルパーメソッド定義時点でデフォルト値を'1'に設定しているので、省略可能。

　　●2つ目：チェックボックスがオフになっている場合。

　　　　➡︎今度は、__テストユーザーがチェックボックスをオフ、すなわちremember_meの値を'0'として、ログインする場合を検証__すればいい。

　　　　　　→log_in_as(＠user,remember_me: '0')
<br>
####1-3.実際にremember meチェックボックスのテストを記述していく
　　●統合テスト、integration/users_login_test.rbファイル内に記述する。

　　　　➡︎setupメソッドにて、テスト用のユーザーusers(:michael)を召喚する。

　　　　　　→fixtureユーザーの参照。

　　●チェックボックスがオンのテスト。

　　　　➡︎チェックボックスがオンのユーザーなので、もちろん1-2で定義したlog_in_as(＠user, remember_me: '1')メソッドを使用。

　　　　➡︎cookiesにremember_tokenキーがちゃんと保存されている事を検証するための記述をする。

　　　　　　→assert_not_empty cookies['remember_token']

　　　　　　→__テスト内では、cookiesメソッドにシンボルが使えないので、文字列を使うことに注意！__

　　●チェックボックスがオフのテスト。

　　　　➡︎一旦、永続クッキー保存してログインさせてからログアウトさせ、クッキーを削除させる処理を明示的に記述する。

　　　　　　→log_in_as(＠user, remember_me: '1')でログインさせる。

　　　　　　→delete logout_pathでログアウトさせ、クッキーを削除させる。

　　　　➡︎次に、チェックボックスがオフの場合のログインテストを記述する。

　　　　　　→log_in_as(＠user, remember_me: '0')で、ログインさせる。

　　　　➡︎cookiesにremember_tokenが保存されておらず、空である事を検証するための記述をする。

　　　　　　→assert_empty cookies['remember_token']
<br>


>```ruby:test/test_helper.rb
class ActiveSupport::TestCase
　
  #省略
　
　#1-1
  def log_in_as(user)
    session[:user_id] = user.id
  end
　
  #1-1
  class ActionDispatch::IntegrationTest
    def log_in_as(user, password: 'password', remember_me: '1')
      post login_path, params: {session: {email:user.email,
                                          password: password,
                                          remember_me: remember_me
                                          }}
  end
end
```

>```ruby:test/integration/users_login_test.rb
  #1-3
  def setup
    @user = users(:michael)
  end
　
  #省略
　
  test "login with remembering" do
    log_in_as(@user, remember_me: '1')
    assert_not_empty cookies['remember_token']
  end
　
  test "login without remembering" do
    log_in_as(@user, remember_me: '1')
    delete logout_path
    log_in_as(@user, remember_me: '0')
    assert_empty cookies['remember_token']
  end
```

<br>

##3.Remember me機能自体のテスト
　　●current_user内の、永続セッションの認証を行う条件分岐に関するテストをまだ行っていないので、これを最後に記述していく。

　　　　➡︎__if user && user.authenticated?(cookies[:remember_token])__の部分。

　　　　　　→「ログインを行った暗号化IDを持つユーザー」と、「ログインした際取得した記憶トークンと、そのユーザーの記憶ダイジェスト」
が存在するかどうかを判定する条件式。
　　
　　●Sessionsヘルパーで、直接テストを行っていく。

　　　　➡︎helpersファイルに、sessions_helper_test.rbファイルを作成する。

　　●テスト行う手順。

　　　　➡︎１：fixtureで、テスト用のユーザーをuser変数で定義する。

　　　　➡︎２：取得したユーザーを、rememberメソッドで記憶する。

　　　　➡︎３：current_userが、取得したユーザーと一致する事を確認する。

　　●永続セッションのテストを、実際に記述する。

　　　　➡︎test/helpers/sessions_helper_test.rbファイル内に記述をしていく。

　　　　　　→setupメソッドを定義する。

　　　　　　　　→手順１に則り、fixtureで定義したユーザーを＠userインスタンス変数へ格納する処理を記述。

　　　　　　　　→手順２に則り、取得した＠userインスタンス変数を、rememberメソッドに渡し記憶させる処理を記述。

　　　　　　→一時セッションがnilの場合に、永続セッションによって正しくログインするテストを記述する。

　　　　　　　　→ログインユーザーが、しっかり＠userであるかどうかを検証する記述をする。

　　　　　　　　→結果、ログインユーザーが存在するかどうかを検証。

　　　　　　→記憶ダイジェストと、記憶トークンが一致しなかった場合、ログインユーザーがnilになる事を確認するテストの記述。

　　　　　　　　→＠userの記憶ダイジェストを、ハッシュ化した記憶トークンで更新する処理を記述する。

　　　　　　　　→ログインユーザーがnilである事を検証するテストを記述する。

　　●結果は、テストスイートはパスする。

<br>

>```ruby:test/helpers/sessions_helper_test.rb
require 'test_helper'
　
class SessionsHelperTest < ActionView::TestCase
　
  def setup
    @user = users(:michael)
    remember(@user)
  end
　
  test "current_user returns right user when session is nil" do
    assert_equal @user, current_user
    assert is_logged_in?
  end
　
  test "current_user returns nil when remember digest is wrong" do
    @user.update_attribute(:remember_digest, User.digest(User.new_token))
    assert_nil current_user
  end
end
```

##参考
　[Railsチュートリアル　第9章発展的なログイン機構](https://railstutorial.jp/chapters/advanced_login?version=5.1#sec-testing_the_remember_branch)