带有可选arg和省略命名params的函数无法接收模型实例

时间:2018-04-15 01:02:30

标签: ruby-on-rails activerecord

我在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中的错误吗?

1 个答案:

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

这种隐式哈希参数行为是关键字参数的前身。