Rails 4 ActiveRecord ::首先不起作用

时间:2017-01-06 20:40:32

标签: ruby-on-rails ruby ruby-on-rails-4 activerecord

我在Rails 4.1应用程序中调试了一些遗留代码,并且我发现了一些令人困惑的结果:

#order.rb

# get the most recent order from the same year we are in
scope :last_from_this_year, -> { where("created_at >= ?", Time.mktime(Time.now.year, 1)).where("created_at < ?", Time.mktime(Time.now.year, 12, 31)).order('payment_id DESC').first }

# orders_controller.rb

prev_payment = Order.last_from_this_year

由于我无法解释的原因,这个范围正在返回包含所有订单记录的ActiveRecord_Relation,尽管事实上它正在调用.first方法。我期待first返回一个ActiveRecord对象。

为什么会这样?

更新

当我在控制台中运行 this 时,它按预期工作:

o = Order.where("created_at >= ?", Time.mktime(Time.now.year, 1)).where("created_at < ?", Time.mktime(Time.now.year, 12, 31)).order('payment_id DESC').first

我确切地复制/粘贴了scope中的内容,并且它有效。因此,为什么它不像预期的范围那样表现出令人困惑。

$  Order.last_from_this_year.to_sql
  =>  SELECT  "orders".* FROM "orders"  WHERE (created_at >= '2017-01-01 08:00:00.000000') AND (created_at < '2017-12-31 08:00:00.000000')  ORDER BY payment_id DESC LIMIT 1

似乎没错......很奇怪。

1 个答案:

答案 0 :(得分:1)

该范围背后的概念是错误。范围的想法是始终返回ActiveRecord :: Relation的实例(对象而不是一个对象的集合),以允许与whereincludes,{{1}等其他方法进一步链接等等。

如果您只需要从该范围中检索一个对象,则需要删除joins并将其用作:.first

其他解决方案是将该代码移至类方法

Order.last_from_this_year.first

然后def self.last_from_this_year where("created_at >= ?", Time.mktime(Time.now.year, 1)) .where("created_at < ?", Time.mktime(Time.now.year, 12, 31)) .order('payment_id DESC') .first end 应该像在控制台上一样工作。