不需要的符号来转换哈希键的字符串
当我在我的控制器中分配时
@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 ==)
为什么这种自动符号转换为字符串? 为什么它会影响哈希的键?
如果Rails以某种方式得到它并且在内部使用字符串键,它可能最终成为HashWithIndifferentAccess
。 您可能想要validation该类是否相同:
assert_equal Hash, assigns(:my_hash).class
参数始终作为无差别访问类型的哈希处理,因此您可以使用字符串或符号进行检索。 如果您在get
或post
调用中将此值分配给params哈希,或者您可能正在转换。
你可以做的另一件事是冻结它,看看是否有人试图修改它,因为这应该抛出exception:
@my_hash = { :my_key => :my_value }.freeze
您可以尝试调用“stringify_keys”:
assigns(:my_hash).should == { :my_key => :my_value }.stringify_keys
AHA! 发生这种情况不是因为Rails本身,而是因为Rspec。
我在控制器规范中测试Hashie::Mash
的值时遇到了同样的问题(但是它适用于任何像Hash
一样Hashie::Mash
东西)
具体来说,在控制器规范中,当您调用assigns
来访问控制器操作中设置的实例变量时,它不会完全返回您设置的实例变量,而是返回HashWithIndifferentAccess
作为HashWithIndifferentAccess
成员存储的变量的副本(包含所有已分配的实例变量)。 不幸的是,当你将Hash
(或任何inheritance自Hash
东西) HashWithIndifferentAccess
到HashWithIndifferentAccess
,它会自动转换为相同的实例,非常方便但不太准确的类:)
最简单的解决方法是通过直接访问变量来避免转换,在“为了您的方便”转换之前,使用: controller.view_assigns['variable_name']
(注意:此处的键必须是字符串,而不是符号)
因此,如果将原始post中的测试更改为:
get 'index' controller.view_assigns['my_hash'].should == { :my_key => :my_value }
(当然,RSpec的新版本不再支持.should
,但仅仅为了比较我保持不变)
有关详细说明,请参阅此文章: http : //ryanogles.by/rails/hashie/rspec/testing/2012/12/26/rails-controller-specs-dont-always-play-nice-with-hashie.html
您还可以将Hash
对象传递给HashWithIndifferentAccess
的初始化HashWithIndifferentAccess
。
您可以使用HashWithIndifferentAccess.new
作为Hash init:
Thor::CoreExt::HashWithIndifferentAccess.new( to: 'mail@somehost.com', from: 'from@host.com')