具有块和if子句的单行ruby句子中的奇怪行为

时间:2013-07-26 08:29:09

标签: ruby-on-rails ruby squeel

我不知道为什么这两段代码在Ruby 1.8.7中表现不同,因为一个似乎是另一个的单行版本。

第一段代码(它可以正常工作):

if @type.present?
  type = @type
  orders = Order.where{type.eq(type)}
end

单行版本(根本不起作用,没有错误,但似乎也没有执行):

orders = Order.where{type.eq(type)} if (type = @type).present?

注意:我正在使用squeel gem,这就是块跟随where方法的原因。此外,变量类型必须捕获实例变量@type,因为执行上下文在块内部发生更改,并且实例变量不在主上下文和块上下文之间共享。

注2:由于遗留原因,我必须使用Ruby 1.8.7。

有什么想法吗?谢谢!

3 个答案:

答案 0 :(得分:5)

解析代码的顺序有问题。变量在使用前需要定义。

即使在if语句子句中定义的变量“泄漏”到当前范围内,它们也不会在Ruby代码中“向后”泄漏。

Ruby有点好奇,需要在解析器解析代码之前定义变量。解析从上到下,从左到右完成。

因此,变量type在您使用它的块代码后定义,它将无法在块中使用。

示例:

>> 3.times { puts x } if (x = 123)
NameError: undefined local variable or method `x' for main:Object

您没有收到任何错误消息的原因是Ruby 1.8 type中的方法是Object#class的同义词。

所以你的代码真正做的是(可能):

orders = Order.where{type.eq(this.class)} if (type = @type).present?

要修复它,您必须在使用之前定义type。因此,除非你只是这样做,否则你不能把它变成单行:

orders = Order.where{type.eq(@type)} if @type.present?

总而言之,在Ruby 1.8中使用type作为Rails模型中的变量并不是一个好主意,因为Object#class问题从长远来看很可能会给您带来麻烦。

答案 1 :(得分:0)

我得到的类似问题是'type'是数据库中的关键字,它允许我们的模型将字段设置为'type',但它在不同条件下工作奇怪。如果更改名称是您的选项,请在更改后检查,为我工作......

答案 2 :(得分:0)

gem Squeel在传递给instance_eval的调用块时使用where方法。因此,在squeel实例中没有任何@type。如果要使用其他上下文中的方法或变量,请尝试将其包含在带有块

的方法my

orders = Order.where { type.eq my { @type } } if @type.present?

对不起我的英文