0

I'm following a Hanami tutorial and I can't work out what's going wrong in this test:

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 results in a failure because "Confident Ruby" does not equal nil.

I can puts params[:book] after the action.call, but sure enough params[:book][:title] is nil. I've tried to access title via other means but can't seem to manage it. It does seem though that params[:book][:title] should be correct.

However, when I use params[:book]['title'], it appears to work. If I try to create a params hash in IRB, params[:book][:title] works, and params[:book]['title'] doesn't, so I remain confused.

I have upgraded to Ruby 2.3.0, but still experience the same behaviour.

params[:book].has_key?(:title) is false, params[:book].has_key?('title') is true. Cross-referencing with the documentation on how to access hash elements, I just don't get it.

What is happening here?

4

2 回答 2

1

这绝不是一个新手问题,因为许多有经验的 Ruby 专家以各种方式在这个话题上苦苦挣扎。简短的回答是,这不是正常的哈希行为,而是 Rails 哈希操作的一个众所周知的问题。您irb对 Hash 的体验是真实的、实际的 Ruby 行为,并且符合您的期望。

所以,真正的问题是,“为什么 Rails 使用哈希来使它们行为不端?” 这是为了支持相当多的用例而做出的一长串决策,包括对参数散列、会话散列和 ActiveRecord 字段名称(例如批量分配)的支持。此功能的最终根源是 Rails 类HashWithIndifferentAccess

HashWithIndifferentAccess所做的是为符号(例如:book, :title)和字符串(例如 'book'、'title')提供等价的哈希键,这样您就不需要知道需要哪种类型的键。因此,indifferent access. 实际上,符号键在访问点内部转换为字符串。它确实解决了一个实际问题,特别是对于刚接触 Ruby 和 Rails 的程序员。然而,在一些最奇怪的地方出现了副作用。RSpec 恰好是那些奇怪的地方之一,并且有各种记录在案的这些副作用的例子。似乎正在发生的事情是原始哈希被转换为 a HashWithIndifferentAccess,它本身是从Hash. 一旦你有一个 的实例HashWithIndifferentAccess,你通常可以把它当作一个Hash,但您必须小心不要将其转换或合并到另一个Hash(或任何其他派生词Hash)。问题在于无关键,并且不明确支持的代码HashWithIndifferentAccess会偶然复制、克隆或合并键的字符串形式,在此过程中丢失符号键的概念。

HashWithIndifferentAccess嵌套哈希最常遇到的问题,展示了您正在经历的确切行为。简而言之,顶级哈希键仍然可以使用符号访问,而嵌套哈希只能使用字符串键访问。

您已经确定了问题的解决方案,那就是使用字符串键从 RSpec 中访问嵌套散列;这个答案只是将原因联系在一起。将您的 RSpec 哈希键定义为字符串而不是符号可能是一个好主意,而且引导起来更容易混淆,这样您就知道字符串键是要使用的正确键。

有关更多信息,您可能有兴趣阅读其中一些文章:

于 2016-05-28T11:23:37.843 回答
0

我很抱歉,但这是一个现已修复的错误。所有参数都可以像这样访问:

params[:book][:title]
于 2017-01-09T08:13:19.883 回答