在测试中访问哈希值

时间:2016-05-26 11:44:30

标签: ruby minitest hanami

我遵循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)falseparams[:book].has_key?('title')true。使用有关如何访问哈希元素的文档进行交叉引用,我只是没有得到它。

这里发生了什么?

2 个答案:

答案 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]