3

从 Rails 应用程序导出 CSV的屏幕截图中,Ryan Bates 展示了以下简单代码。

我试图弄清楚类方法 Product::to_csv 实际上是如何在 ProductController.rb 的第 5 行被调用的,因为它似乎不遵循正常的 Ruby 规则。

产品.rb

1 class Product < ActiveRecord::Base   
2   def self.to_csv(options = {})
3     ...
4   end
5 end

products_controller.rb

1 class ProductsController < ApplicationController
2  def index
3    @products = Product.order(:name)
4    respond_to do |format|
5      format.csv { send_data @products.to_csv }
6      ...
7    end
8  end
9 end

由于 to_csv 是一个类方法,我希望调用看起来像 Product::to_csv()。

根据文档,@products 是 ActiveRecord::Relation 的一个实例。为什么发送到 ActiveRecord::Relation 实例的消息会导致 Product 类对象上的方法被调用?更奇怪的是,在发送方和接收方中将 to_csv 重命名为任意名称会导致 NoMethodError,所以也许有一些基于以 to_ 开头的名称的魔法正在发生?

我错过了一些明显的东西吗?任何澄清将不胜感激。

4

2 回答 2

3

这只是 Rails 所做的事情之一。任何类方法都会自动成为“集合”方法,这意味着它们可用于关系对象。范围和类方法可以这样互换。

于 2012-07-21T00:06:16.720 回答
1

我现在可以回答以下问题:

为什么发送到 ActiveRecord::Relation 实例的消息会导致 Product 类对象上的方法被调用?

ActiveRecord::Relation类用于链接多个方法,而不会实际触发多个 SQL 查询。这样你就可以编写类似的东西Product.where('price <= ?', 100).order(:price).limit(30),Rails 只会执行一个查询。

魔术之所以有效,是因为在ActiveRecord::Relation您尝试访问数据之前(例如,因为一个firstall调用),您有一个实例,那时查询将运行并且您将拥有ActiveRecord::Base一个或他的后代之一。

长话短说,如果你检查类,@products.class你会看到是一个ActiveRecord::Relation但后来你有Product实例,然后你可以调用该to_csv方法。

于 2012-07-20T22:59:11.940 回答