Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

はじめに

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 を調べる

https://github.com/rails/rails/blob/master/actionpack/lib/action_dispatch/middleware/cookies.rb#L315L317

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

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

Rack::Test::CookieJar を調べる

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

https://github.com/brynary/rack-test/blob/master/lib/rack/test/cookie_jar.rb#L108-L112

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が親切すぎる?

感想

  • こういう内容こそ、チュートリアル内で深掘りして欲しいと思いました。
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away