`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
每个值采用 默认值 ,offset
为 1 * default
。等价于 SQL 是 -
SELECT "model_names".* FROM "model_names" LIMIT 20 OFFSET 20
当您执行 ModelName.page(1).per(5)
时,limit
将 5
作为每个值,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
我不明白这种方法在这种情况下是如何工作的:
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
每个值采用 默认值 ,offset
为 1 * default
。等价于 SQL 是 -
SELECT "model_names".* FROM "model_names" LIMIT 20 OFFSET 20
当您执行 ModelName.page(1).per(5)
时,limit
将 5
作为每个值,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