Как заставить метод применяться к коллекции объектов ActiveRecord? - PullRequest
9 голосов
/ 22 октября 2008

В настоящее время, если я хочу применить метод к группе объектов 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 ]

6 голосов
/ 25 октября 2008

Следующие вызовет 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
}
3 голосов
/ 23 ноября 2008

Поместите это в файл в 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 голосов
/ 22 октября 2008

FasterCSV исправляет класс Array и добавляет к нему метод 'to_csv' , но он не выполняет то, что вам нужно. Вы можете перезаписать это самостоятельно, выполнив что-то вроде:

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

Или что-то в этом роде, но это вроде дерьмо.

Честно говоря, это более логично, как метод класса в вашей модели.

0 голосов
/ 03 июля 2013

Я знаю, что это очень старый вопрос, но я все равно подумал об обратной связи. проверить блог http://blog.zahiduzzaman.com/2013/07/adding-tocsv-method-to-active-record.html просто еще один способ достижения этого

0 голосов
/ 29 марта 2009

Если он изолирован от одной модели 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

Это из памяти, но должно работать.

0 голосов
/ 22 октября 2008

Вы можете определить метод непосредственно для самого объекта 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 или нет: то есть я не уверен, насколько распространенным или приемлемым является определение новых методов непосредственно в экземплярах объекта, я знаю только это возможно; -)

0 голосов
/ 22 октября 2008

Вы можете создать метод в своем классе 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...