はじめに
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
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
[] メソッドをオーバーライドして、引数 name を to_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
こちらも [] メソッドをオーバーライドしてますが、引数 name を to_s していません。
まとめ
- railsとrack-testで
[]メソッドのオーバーライドの仕方が異なるため、使える引数の種類が異なってしまっている。 - rack-testでも、
name.to_sとすれば動きそう。 - どっちのやり方が正しいかわからないが、イメージ的にrailsが親切すぎる?
感想
- こういう内容こそ、チュートリアル内で深掘りして欲しいと思いました。
