Ruby on rails 哈希键的不需要的符号到字符串转换
当我在控制器中分配Ruby on rails 哈希键的不需要的符号到字符串转换,ruby-on-rails,unit-testing,testing,rspec,rspec2,Ruby On Rails,Unit Testing,Testing,Rspec,Rspec2,当我在控制器中分配 @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 ==) 为什么会发生这种符号到字符串的自动转换?为什么它
@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以某种方式控制了它,并且在内部使用了字符串键,那么它可能会以无差异访问的
散列结束。您可能希望验证该类是否相同:
assert_equal Hash, assigns(:my_hash).class
参数总是作为一种散列进行处理,因此您可以使用字符串或符号进行检索。如果您在get
或post
调用中将其分配给您的params散列,或者您可能正在转换
您可以做的另一件事是冻结它,并查看是否有人试图修改它,因为这会引发异常:
@my_hash = { :my_key => :my_value }.freeze
您可以尝试调用“stringify_keys”:
您还可以将Hash
对象传递给hashWithInferenceTaccess
的初始值设定项。您可以使用hashWithInferenceTaccess。新的作为Hash init:
Thor::CoreExt::HashWithIndifferentAccess.new( to: 'mail@somehost.com', from: 'from@host.com')
啊哈!这不是因为Rails本身,而是因为Rspec
我在控制器规范中测试Hashie::Mash
的值时遇到了同样的问题(但它适用于任何像Hash
这样的庸医)
具体地说,在控制器规范中,当您调用assigns
以访问控制器操作中设置的实例变量时,它并没有准确返回您设置的实例变量,而是返回Rspec存储为hashWithInferenceAccess的成员的变量副本(包含所有分配的实例变量)。不幸的是,当您将散列
(或从散列
继承的任何内容)粘贴到散列中时,它会自动转换为同一类的实例,哦,非常方便,但不是很准确:)
最简单的解决方法是,在转换变量之前,使用:controller.view\u assigns['variable\u name']
(注意:此处的键必须是字符串,而不是符号),直接访问变量以避免转换
因此,如果将原始帖子中的测试更改为:
get 'index'
controller.view_assigns['my_hash'].should == { :my_key => :my_value }
(当然,.should
在新版本的RSpec中不再受支持,但为了便于比较,我保持不变)
有关更多说明,请参阅本文:
我知道这很旧,但如果您从Rails-3升级到4,您的控制器测试可能仍有使用符号键的哈希
,但与字符串化版本相比,只是为了防止错误的预期
Rails-4已修复此问题:。
我建议更新您的测试,使其具有与实际密钥相对应的期望值
在Rails-3中,assigns
方法将您的@my_hash
转换为hashWithInferenceAccess
,该方法将所有键字符串化-
def assigns(key = nil)
assigns = @controller.view_assigns.with_indifferent_access
key.nil? ? assigns : assigns[key]
end
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
你真的应该设置你的Gravatar,因为你的用户名太棒了。它确实是一个无所谓的hashWith Access。我有点奇怪为什么Rails会将我的标准哈希转换成那个。我不会将其分配给上述以外的任何对象(尤其是不分配给params)。您可能还知道为什么Rails在控制器和视图之间进行转换(如上所述,在上面的示例中没有使用参数),这似乎有点愚蠢,为什么要将其转换为hashWithInferenceTaccess
Rails会自动将传入参数转换为Inference access散列,这样在引用它时就不必担心字符串或符号了params[:foo]
和params['foo']
最终是等效的。这可能在某种程度上是为了帮助不习惯对键进行符号化的PHP、Perl和Python开发人员,并避免记住键的存储形式。我不认为是Rails,而是Rspec导致了这个问题。我也有同样的问题。我将尝试在下面发布一个答案,因为这个问题是在我搜索我的问题时提出的,即使它已经5年了!;)这篇文章解释了更多:解决了我的问题。。您知道任何处理嵌套哈希的方法吗?链接404现在:(如果其他人仍在寻找答案中发布的链接,
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