“extending”方法是如何在ActiveRecord中工作的



我不明白这个方法在这种情况下是如何工作的:

def self.page(page)
  limit(default).offset(page * default).extending do
  def per(num)
    limit(num).offset(page * num)
  end
end

它与原始代码有点不同。

我们可以使用ModelName.page(1).per(5)。我真的很困惑它是怎么工作的。看起来发生了什么魔法。

作为延伸语-

用于通过提供的模块或块,使用其他方法扩展作用域。返回的对象是一个可以进一步扩展的关系。

这里有一个小例子来说明这个功能:

Spree::Order.class_eval do
  def self.scope_cart
    self.where(currency: "INR").extending do
      def orders_in_cart
        where.not(state: 'cart')
      end
    end
  end
end
Spree::Order.scope_cart.count # => 367
# SQl code
# SELECT COUNT(*) FROM "spree_orders"  WHERE "spree_orders"."currency" = 'INR'
Spree::Order.count # => 367

到目前为止,您可以看到scope_cart正在给我数据计数,这是self.where(currency: "INR")的结果。好吧,现在让我们看看orders_in_cart给了我们什么新方法

Spree::Order.scope_cart.orders_in_cart.count # => 342
# SQL code
# SELECT COUNT(*) FROM "spree_orders"  WHERE "spree_orders"."currency" = 'INR' AND ("spree_orders"."state" != 'cart')

注意:注意针对两种不同情况的SQL代码。这就是你问题的答案。

现在再举你的例子。当你调用ModelName.page(1)时,你会得到这个limit(default).offset(page * default)的结果。现在,如果您想要额外的筛选,您将调用per方法作为ModelName.page(1).per(5),然后您将从limit(num).offset(page * num)获得结果,该结果被应用于limit(default).offset(page * default)的结果

进一步扩展:

执行ModelName.page(1)时,limit采用默认每个值,offset1 * default。等效SQL是-

SELECT  "model_names".* FROM "model_names"  LIMIT 20 OFFSET 20

执行ModelName.page(1).per(5)时,limit5作为每个值,offset作为1 * 5。等效SQL是-

SELECT  "model_names".* FROM "model_names"  LIMIT 5 OFFSET 5

在Rails中,我在文档中看到,如果你像User.limit(10).limit(20)一样编写,它会生成SQL。它有LIMIT 20,这意味着它使用链中最后一个limit子句。trueoffset相同。

查看控制台生成的SQL代码:

Spree::Order.limit(20).offset(2).limit(5).offset(5)
# Spree::Order Load (0.5ms)  SELECT  "spree_orders".* FROM "spree_orders"  LIMIT 5 OFFSET 5

最新更新