`extending` 方法在 ActiveRecord 中如何工作?

How does the `extending` method work in ActiveRecord?

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

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

the original code有点不同。

我们可以使用ModelName.page(1).per(5)。我真的很困惑它是如何工作的。好像发生了什么魔法。

extending所说-

Used to extend a scope with additional methods, either through a module or through a block provided. The object returned is a relation, which can be further extended.

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

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代码,对于2个不同个案。这里有你问题的答案。

现在再来看你的例子。当您调用 ModelName.page(1) 时,您将得到此 limit(default).offset(page * default) 的结果。现在,如果您想要额外的过滤,您将调用 per 方法作为 ModelName.page(1).per(5),然后您将从 limit(num).offset(page * num) 获得结果,即 applied根据 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,我看到在documentation如果你写成User.limit(10).limit(20),它生成SQL有LIMIT 20,意味着它取last limit 链中的子句。对于 offset.

也是 true

查看控制台生成的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