如何使方法适用于ActiveRecord对象的集合

目前,如果我想将一个方法应用于一组ActiveRecord对象,我必须像这样构造调用:

messages = Message.find(:all) csv = Message.to_csv(messages) 

如何定义方法,使其结构如此?

 messages = Message.find(:all) csv = messages.to_csv 

这是当前的型号代码:

 require 'fastercsv' class Message < ActiveRecord::Base def Message.to_csv(messages) FasterCSV.generate do |csv| csv << ["from","to", "received"] for m in messages csv << [m.from,m.to,m.created_at] end end end end 

以下内容将在messages数组中包含的所有实例上调用to_csv。

 messages = Message.find(:all) csv = messages.map { |message| message.to_csv } 

在Rails中,在Ruby 1.9中或通过其他方式使用Symbol#to_proc,您还可以将其缩短为:

 csv = messages.map(&:to_csv) 

当您想要进行更复杂的操作时,较长的forms很有用:

 csv = messages.map { |message| if message.length < 1000 message.to_csv else "Too long" end } 

把它放在lib /中的文件中。 我建议把它base_ext.rb

 require 'fastercsv' class ActiveRecord::Base def self.to_csv(objects, skip_attributes=[]) FasterCSV.generate do |csv| csv << attribute_names - skip_attributes objects.each do |object| csv << (attribute_names - skip_attributes).map { |a| "'#{object.attributes[a]}'" }.join(", ") end end end end 

之后,转到config / environment.rb并在文件底部放置require 'base_ext'以包含新扩展名。 重新启动服务器后,您应该可以访问所有模型类上的to_csv方法,当您传递它时,对象数组应该为您生成一个漂亮的CSV格式。

FasterCSV修补了Array类,并且已经为它添加了一个’to_csv’方法,但是它没有做你想要的。 您可以通过执行以下操作来自己覆盖它:

 class Array def to_csv(options = Hash.new) collect { |item| item.to_csv }.join "\n" end end 

或者沿着这些方向的东西,但那有点糟糕。

老实说,作为模型上的类方法,它更有意义。

您可以在Message类上创建一个方法来执行某些操作……

在你的控制器….

 @csv_file = Message.send_all_to_csv 

在你的模特中……

 require 'fastercsv' class Message < ActiveRecord::Base def send_all_to_csv @messages = Find.all FasterCSV.generate do |csv| csv << ["from","to", "received"] for message in @messages csv << [message.from,message.to,message.created_at] end end # do something with your csv object (return it to the controller # or pass it on to another class method end end 

您可以直接在messages对象本身上定义方法,但是如果您这样做,该方法只能用于该特定实例:

 def messages.to_csv() FasterCSV.generate do |csv| csv << ["from", "to", "received"] self.each { |m| csv << [m.from, m.to, m.created_at] } end end 

然后你可以像这样调用它:

 messages.to_csv 

我是一个Ruby新手,所以我不确定这是否是惯用的Ruby:也就是说,我不确定在对象实例上直接定义新方法有多常见或被接受,我只知道它是可能的; - )

如果它被隔离到一个AR模型,我会添加一个to_custom_csv_array实例方法

 def to_custom_csv_array [self.from,self.to,self.created_at] end 

然后覆盖类上的查找

 def self.find(*args) collection = super collection.extend(CustomToCSV) if collection.is_a?(Array) end 

并在CustomToCSV中定义to_custom_csv以生成csv

 module CustomToCSV def to_custom_csv FasterCSV.generate do |csv| csv << ["from","to", "received"] csv << self.map {|obj| obj.to_custom_csv_array} end end end 

这是从内存,但应该工作。

我知道这是一个非常古老的问题,但只是想提供一个反馈意见。 查看博客http://blog.zahiduzzaman.com/2013/07/adding-tocsv-method-to-active-record.html只是实现这一目标的另一种方式