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

时间:2008-10-22 00:59:31

标签: ruby-on-rails ruby

目前,如果我想将一个方法应用于一组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

7 个答案:

答案 0 :(得分:6)

以下内容将在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)

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

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

答案 1 :(得分:3)

将其放入 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格式。

答案 2 :(得分:2)

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

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

或者那些东西,但那有点糟糕。

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

答案 3 :(得分:0)

您可以在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

答案 4 :(得分:0)

您可以直接在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:也就是说,我不确定直接在对象实例上定义新方法有多普遍或被接受,我只知道这是可能的; - )

答案 5 :(得分:0)

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

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

然后覆盖类

上的find
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

这是来自记忆但应该有用。

答案 6 :(得分:0)

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