はじめに
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が親切すぎる?
感想
- こういう内容こそ、チュートリアル内で深掘りして欲しいと思いました。