我遵循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
导致失败,因为"自信的红宝石"不等于零。
我可以puts params[:book]
之后action.call
,但确定params[:book][:title]
是nil
。我尝试通过其他方式访问title
,但似乎无法管理它。虽然params[:book][:title]
应该是正确的,但似乎确实如此。
但是,当我使用params[:book]['title']
时,它似乎有效。如果我尝试在IRB中创建一个params散列,params[:book][:title]
有效,params[:book]['title']
没有,所以我仍然感到困惑。
我已升级到Ruby 2.3.0,但仍然遇到相同的行为。
params[:book].has_key?(:title)
为false
,params[:book].has_key?('title')
为true
。使用有关如何访问哈希元素的文档进行交叉引用,我只是没有得到它。
这里发生了什么?
答案 0 :(得分:1)
这绝不是一个 newbie 问题,因为许多有经验的Rubyists以各种方式与这个话题斗争。简短的回答是,这不是正常哈希行为,但是Rails哈希操作是一个有点已知的问题。您对Hash的irb
经验是真实的,实际的Ruby行为,并且符合您的期望。
所以,真正的问题是,“为什么Rails用哈希来捣乱他们行为不端?”这是为支持相当多的用例而做出的一系列长期决策,包括对params哈希,会话哈希和ActiveRecord字段名称(例如质量分配)的支持。此功能的最终根源是Rails类HashWithIndifferentAccess
。
HashWithIndifferentAccess
所做的是为符号(例如:book
,:title
)和字符串(例如'book','title')提供等效的哈希键,以便您不要我需要知道需要哪种类型的密钥。因此,indifferent access
。实际上,符号键在访问点内部转换为字符串。它确实解决了一个实际问题,特别是对于Ruby和Rails的新手程序员。然而,在一些最奇怪的地方出现了副作用。 RSpec恰好是那些奇怪的地方之一,并且已经有各种记录的这些副作用的例子。
似乎正在发生的事情是原始哈希转换为HashWithIndifferentAccess
,它本身派生自Hash
。在您拥有HashWithIndifferentAccess
的实例后,您通常可以将其视为Hash
,但您必须小心不要将其转换或合并到另一个Hash
(或其他任何衍生产品) Hash
)。问题在于无关紧要的密钥,并且没有明确支持HashWithIndifferentAccess
的代码会偶然复制,克隆或合并密钥的字符串形式,从而丢失过程中符号密钥的概念。
嵌套哈希最常遇到HashWithIndifferentAccess
的问题,展示了您遇到的确切行为。简而言之,仍然可以使用符号访问顶级哈希键,而嵌套哈希只能使用字符串键访问。
您已经确定了问题的解决方案,那就是使用字符串键从RSpec中访问嵌套哈希值;这个答案只是为了把原因联系在一起。将启动RSpec哈希键定义为字符串而不是符号,这可能是一个好主意,并且不那么令人困惑,因此您知道字符串键是正确使用的键。
有关更多信息,您可能有兴趣阅读其中一些文章:
答案 1 :(得分:0)
对不起,但这是一个现在修复的错误。可以访问所有参数:
params[:book][:title]