在测试中访问哈希值
Accessing Hash Value in Test
我正在学习 Hanami 教程,但我无法弄清楚此测试中出了什么问题:
describe Web::Controllers::Books::Create do
let(:action) { Web::Controllers::Books::Create.new }
let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
it 'creates a new book' do
action.call(params)
action.book.id.wont_be_nil
action.book.title.must_equal params[:book][:title]
end
end
rake test
导致失败,因为 "Confident Ruby" 不等于 nil。
我可以在action.call
之后puts params[:book]
,但是params[:book][:title]
果然是nil
。我尝试通过其他方式访问 title
但似乎无法管理它。看来 params[:book][:title]
应该是正确的。
但是,当我使用 params[:book]['title']
时,它似乎有效。如果我尝试在 IRB 中创建一个参数散列,params[:book][:title]
有效,而 params[:book]['title']
无效,所以我仍然感到困惑。
我已经升级到 Ruby 2.3.0,但仍然遇到同样的问题。
params[:book].has_key?(:title)
是 false
,params[:book].has_key?('title')
是 true
。交叉引用有关如何访问哈希元素的文档,我只是不明白。
这里发生了什么?
这绝不是一个 新手 问题,因为许多有经验的 Ruby 爱好者以各种方式与这个话题作斗争。简短的回答是,这不是 正常的 哈希行为,而是 Rails 哈希操作的一个已知问题。您对 Hash 的 irb
体验是真实的 Ruby 行为,并且符合您的期望。
所以,真正的问题是,"why does Rails muck with hashes to make them misbehave?"这是为支持相当多的用例而做出的一系列很长很长的决定,包括对参数哈希、会话哈希和 ActiveRecord 字段名称的支持(例如批量分配)。此功能的最终根源是 Rails class HashWithIndifferentAccess
.
HashWithIndifferentAccess
所做的是为符号(例如 :book
、:title
)和字符串(例如 'book'、'title')提供散列键的等效性,这样您就不需要知道需要哪种类型的密钥。因此,indifferent access
。实际上,符号键在访问点内部转换为字符串。它确实解决了一个实际问题,特别是对于 Ruby 和 Rails 的新程序员。然而,在一些最奇怪的地方出现了副作用。 RSpec 恰好是那些奇怪的地方之一,并且有各种这些副作用的记录示例。
似乎正在发生的事情是原始哈希被转换为 HashWithIndifferentAccess
,它本身是从 Hash
派生的。一旦你有了 HashWithIndifferentAccess
的实例,你通常可以像 Hash
一样对待它,但你必须小心不要将它转换或合并到另一个 Hash
(或任何其他派生的Hash
)。问题在于无关紧要的键,不明确支持 HashWithIndifferentAccess
的代码会顺便复制、克隆或合并键的字符串形式,从而在过程中丢失符号键的概念。
HashWithIndifferentAccess
的问题在嵌套哈希中最常遇到,展示了您遇到的确切行为。简而言之,顶级哈希键仍然可以使用符号访问,而嵌套哈希只能使用字符串键访问。
您已经确定了问题的解决方案,那就是使用字符串键从 RSpec 中访问嵌套哈希;这个答案只是为了将原因联系在一起。将 RSpec 散列键定义为字符串而不是符号可能是个好主意,而且启动起来更容易混淆,这样您 就知道 字符串键是正确的要使用的键。
如需了解更多信息,您可能有兴趣阅读其中的一些文章:
抱歉,这是一个错误,现在已修复。所有参数都可以像这样访问:
params[:book][:title]
我正在学习 Hanami 教程,但我无法弄清楚此测试中出了什么问题:
describe Web::Controllers::Books::Create do
let(:action) { Web::Controllers::Books::Create.new }
let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
it 'creates a new book' do
action.call(params)
action.book.id.wont_be_nil
action.book.title.must_equal params[:book][:title]
end
end
rake test
导致失败,因为 "Confident Ruby" 不等于 nil。
我可以在action.call
之后puts params[:book]
,但是params[:book][:title]
果然是nil
。我尝试通过其他方式访问 title
但似乎无法管理它。看来 params[:book][:title]
应该是正确的。
但是,当我使用 params[:book]['title']
时,它似乎有效。如果我尝试在 IRB 中创建一个参数散列,params[:book][:title]
有效,而 params[:book]['title']
无效,所以我仍然感到困惑。
我已经升级到 Ruby 2.3.0,但仍然遇到同样的问题。
params[:book].has_key?(:title)
是 false
,params[:book].has_key?('title')
是 true
。交叉引用有关如何访问哈希元素的文档,我只是不明白。
这里发生了什么?
这绝不是一个 新手 问题,因为许多有经验的 Ruby 爱好者以各种方式与这个话题作斗争。简短的回答是,这不是 正常的 哈希行为,而是 Rails 哈希操作的一个已知问题。您对 Hash 的 irb
体验是真实的 Ruby 行为,并且符合您的期望。
所以,真正的问题是,"why does Rails muck with hashes to make them misbehave?"这是为支持相当多的用例而做出的一系列很长很长的决定,包括对参数哈希、会话哈希和 ActiveRecord 字段名称的支持(例如批量分配)。此功能的最终根源是 Rails class HashWithIndifferentAccess
.
HashWithIndifferentAccess
所做的是为符号(例如 :book
、:title
)和字符串(例如 'book'、'title')提供散列键的等效性,这样您就不需要知道需要哪种类型的密钥。因此,indifferent access
。实际上,符号键在访问点内部转换为字符串。它确实解决了一个实际问题,特别是对于 Ruby 和 Rails 的新程序员。然而,在一些最奇怪的地方出现了副作用。 RSpec 恰好是那些奇怪的地方之一,并且有各种这些副作用的记录示例。
似乎正在发生的事情是原始哈希被转换为 HashWithIndifferentAccess
,它本身是从 Hash
派生的。一旦你有了 HashWithIndifferentAccess
的实例,你通常可以像 Hash
一样对待它,但你必须小心不要将它转换或合并到另一个 Hash
(或任何其他派生的Hash
)。问题在于无关紧要的键,不明确支持 HashWithIndifferentAccess
的代码会顺便复制、克隆或合并键的字符串形式,从而在过程中丢失符号键的概念。
HashWithIndifferentAccess
的问题在嵌套哈希中最常遇到,展示了您遇到的确切行为。简而言之,顶级哈希键仍然可以使用符号访问,而嵌套哈希只能使用字符串键访问。
您已经确定了问题的解决方案,那就是使用字符串键从 RSpec 中访问嵌套哈希;这个答案只是为了将原因联系在一起。将 RSpec 散列键定义为字符串而不是符号可能是个好主意,而且启动起来更容易混淆,这样您 就知道 字符串键是正确的要使用的键。
如需了解更多信息,您可能有兴趣阅读其中的一些文章:
抱歉,这是一个错误,现在已修复。所有参数都可以像这样访问:
params[:book][:title]