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

时间:2015-03-27 09:39:13

标签: ruby-on-rails ruby kaminari

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

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)。关于它是如何工作的我真的很困惑。看起来有些神奇的事情发生了。

1 个答案:

答案 0 :(得分:2)

正如extending所说 -

  

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

这是一个用于说明此功能的小例子:

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)的结果,该结果已应用 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取值,offset1 * 5。等效的SQL是 -

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

在Rails中,我在documentation中看到如果你写的是User.limit(10).limit(20),它会生成SQL LIMIT 20,意味着它需要最后 {{1链中的子句。 limit的{​​{1}}也相同。

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

true