我在Rails中遇到了一些非常令人困惑的行为。
(Ruby v2.3.1p112,Rails v4.2.4)
如果我调用一个接受可选参数和命名参数的方法,并且只给它一个模型实例,那么该模型实例将被转换为哈希。为什么呢?
具体而言:def test(a=nil, b:nil)
与test(merchant_instance)
一起调用时会收到Hash
,而不是Merchant
。
任何其他方法签名或调用都不会重现此行为。
考虑以下三种方法:
def test_one(a=nil)
# This one always works
raise ArgumentError, "Received a #{a.class}"
end
def test_two(a=nil, b:nil)
# This one only works when I also specify `b`
raise ArgumentError, "Received a #{a.class}"
end
def test_three(a, b:nil)
# This one also always works
raise ArgumentError, "Received a #{a.class}"
end
这些调用按预期接收Merchant
个实例:
test_one( Merchant.find(42) )
test_two( Merchant.find(42), b:nil )
test_three( Merchant.find(42), b:nil )
test_three( Merchant.find(42) )
这是唯一一个收到Hash
:
test_two( Merchant.find(42) )
经过进一步测试,这些方法签名在仅给出单个arg时也会收到Merchant
实例:
def test(a:nil, b:nil)
def test(a=nil, b=nil)
这意味着只有当方法签名包含一个可选的arg AND可选命名args时,并且只有在调用时未指定命名的args时才会发生此Hash转换。
为什么会这样?
这是ActiveRecord中的错误吗?
答案 0 :(得分:0)
我认为这不是ActiveRecord中的错误,更可能是您正在使用的红宝石中的错误。
它实际上是将ActiveRecord对象转换为Hash,还是将参数列表转换为哈希?因为在ruby中,如果你没有使用关键字参数,你仍然可以像这样调用:
def my_method(obj=nil)
puts obj.inspect
end
my_method(a: nil, b: nil)
应打印{:a=>nil, :b=>nil}
。
这种隐式哈希参数行为是关键字参数的前身。