LoginSignup
21
11

More than 5 years have passed since last update.

Railsチュートリアル内の「テスト内ではcookiesメソッドにシンボルを使用できない」という問題

Last updated at Posted at 2017-01-18

はじめに

Ruby on Rails チュートリアル日本語訳版(第4版)の第9章にて、「テスト内では cookies メソッドにシンボルが使用できない」問題があるとの記述がありました。

実はもう1つ地味な問題があります (筆者はこれで何時間も躓いてしまいました...)。テスト内ではcookiesメソッドにシンボルを使用できない、という問題です。そのため、

cookies[:remember_token]

上のコードは常にnilになってしまいます。 ありがたいことに、文字列キーならcookiesで使用できるので、

cookies['remember_token']

上のように書けば期待どおりに値が返されます。

Ruby on Railsチュートリアル日本語訳版第4版 9.3.1 [Remember me] ボックスをテストする より引用
https://railstutorial.jp/chapters/advanced_login?version=5.0#sec-testing_the_remember_me_box

これがなぜなのか調べてみました。

cookies メソッドは何者なのか?

Rails上では何のオブジェクトなのか?

まず、 web-console で見てみます。

class StaticPagesController < ApplicationController

  def home
+   console
  end

web-console.png

ActionDispatch::Cookies::CookieJar のインスタンスです。
String、Symbolの両方のキーでvalueにアクセスができます。

ユニットテスト上では何のオブジェクトなのか?

次に、ユニットテストで binding.pry をして調べてみます。

  test "login with remembering" do
    log_in_as(@user, remember_me: '1')
+   binding.pry
    assert_equal cookies['remember_token'], assigns(:user).remember_token
  end
$ rails test test/integration/users_login_test.rb
Run options: --seed 11138

# Running:


From: test/integration/users_login_test.rb @ line 43 UsersLoginTest#test_login_with_remembering:

    40: test "login with remembering" do
    41:   log_in_as(@user, remember_me: '1')
    42:   binding.pry
 => 43:   assert_equal cookies['remember_token'], assigns(:user).remember_token
    44: end

[1] pry(#<UsersLoginTest>)> cookies.class
=> Rack::Test::CookieJar
[2] pry(#<UsersLoginTest>)> cookies['remember_token']
=> "xosbwurfBfRnYu5Y5XBjpA"
[3] pry(#<UsersLoginTest>)> cookies[:remember_token]
=> nil

こちらは Rack::Test::CookieJar のインスタンスです。
チュートリアルの通り、Symbolではvalueにアクセスができません。

ActionDispatch::Cookies::CookieJar を調べる

def [](name)
  @cookies[name.to_s]
end

[] メソッドをオーバーライドして、引数 nameto_sして必ずStringに直すようにすることで
String、Symbol両方でvalueにアクセスできるようになってるんですね。

Rack::Test::CookieJar を調べる

一方、こちらはどうでしょうか?

def [](name)
  cookies = hash_for(nil)
  # TODO: Should be case insensitive
  cookies[name] && cookies[name].value
end

こちらも [] メソッドをオーバーライドしてますが、引数 nameto_s していません。

まとめ

  • railsとrack-testで [] メソッドのオーバーライドの仕方が異なるため、使える引数の種類が異なってしまっている。
  • rack-testでも、 name.to_s とすれば動きそう。
  • どっちのやり方が正しいかわからないが、イメージ的にrailsが親切すぎる?

感想

  • こういう内容こそ、チュートリアル内で深掘りして欲しいと思いました。
21
11
4

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
21
11