如何使方法适用于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只是实现这一目标的另一种方式