14

当我在我的控制器中分配时

@my_hash = { :my_key => :my_value }

并通过执行测试该控制器

get 'index'
assigns(:my_hash).should == { :my_key => :my_value }

然后我收到以下错误消息:

expected: {:my_key=>:my_value},
got: {"my_key"=>:my_value} (using ==)

为什么会发生这种自动符号到字符串的转换?为什么它会影响哈希的键?

4

6 回答 6

8

您可以尝试调用“stringify_keys”:

assigns(:my_hash).should == { :my_key => :my_value }.stringify_keys
于 2010-12-10T19:19:35.280 回答
7

HashWithIndifferentAccess如果 Rails 以某种方式获得它,并且在内部使用字符串键,它可能最终会结束。您可能想要验证类是否相同:

assert_equal Hash, assigns(:my_hash).class

参数总是作为无差别访问类型的哈希处理,因此您可以使用字符串或符号进行检索。如果您将其分配给getorpost调用上的 params 散列,或者您可能会被转换。

您可以做的另一件事是冻结它并查看是否有人尝试修改它,因为这应该引发异常:

@my_hash = { :my_key => :my_value }.freeze
于 2010-12-03T18:08:17.583 回答
1

啊哈!这不是因为 Rails 本身,而是因为 Rspec。

我在控制器规范中测试 a 的值时遇到了同样的问题Hashie::Mash(但它适用于任何像 a 一样嘎嘎作响的东西Hash

具体来说,在控制器规范中,当您调用assigns以访问控制器操作中设置的实例变量时,它不会返回您设置的实例变量,而是 Rspec 存储为 a 成员的变量的副本HashWithIndifferentAccess(包含所有分配的实例变量)。不幸的是,当您将 a Hash(或任何继承自的东西Hash)粘贴到 aHashWithIndifferentAccess中时,它会自动转换为相同的、非常方便但不太准确的类的实例:)

最简单的解决方法是通过直接访问变量来避免转换,在“为了您的方便”进行转换之前,使用:(controller.view_assigns['variable_name']注意:这里的键必须是字符串,而不是符号)

因此,如果将原始帖子中的测试更改为:

get 'index'
controller.view_assigns['my_hash'].should == { :my_key => :my_value }

(当然,.should新版本的 RSpec 不再支持,但只是为了比较我保持不变)

有关进一步说明,请参阅本文: http ://ryanogles.by/rails/hashie/rspec/testing/2012/12/26/rails-controller-specs-dont-always-play-nice-with-hashie.html

于 2015-07-21T22:07:15.677 回答
1

我知道这是旧的,但如果你从 Rails-3 升级到 4,你的控制器测试可能仍然有Hash使用符号键但与字符串化版本相比的地方,只是为了防止错误的期望。

Rails-4 已修复此问题:https ://github.com/rails/rails/pull/5082 。我建议更新您的测试以对实际键有期望。

在 Rails-3 中,该assigns方法将您转换@my_hashHashWithIndifferentAccess字符串化所有键 -

def assigns(key = nil)
  assigns = @controller.view_assigns.with_indifferent_access
  key.nil? ? assigns : assigns[key]
end

https://github.com/rails/rails/blob/3-2-stable/actionpack/lib/action_dispatch/testing/test_process.rb#L7-L10

Rails-4 更新它以返回原始密钥 -

def assigns(key = nil)
  assigns = {}.with_indifferent_access
  @controller.view_assigns.each { |k, v| assigns.regular_writer(k, v) }
  key.nil? ? assigns : assigns[key]
end

https://github.com/rails/rails/blob/4-0-stable/actionpack/lib/action_dispatch/testing/test_process.rb#L7-L11

于 2019-05-08T07:20:24.207 回答
0

您还可以将Hash对象传递给HashWithIndifferentAccess.

于 2011-08-08T23:02:00.227 回答
0

您可以HashWithIndifferentAccess.new用作哈希初始化:

Thor::CoreExt::HashWithIndifferentAccess.new( to: 'mail@somehost.com', from: 'from@host.com')
于 2014-07-19T13:15:45.240 回答