如何调用这个Ruby类方法?

在使用rails应用程序导出CSV的屏幕上,Ryan Bates提供了以下简单代码。

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

product.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()。

根据文档,@ product是ActiveRecord :: Relation的一个实例。 为什么发送到ActiveRecord :: Relation实例的消息会导致调用Product类对象的方法? 为了使它更奇怪,在发送方和接收方中将to_csv重命名为某个任意名称会导致NoMethodError,所以也许根据以to_开头的名称进行一些神奇的冒险?

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

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

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

为什么发送到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方法。