2008-10-22 8 views
8

Actualmente, si quiero aplicar un método a un grupo de objetos ActiveRecord, tengo que estructurar la llamada de esta manera:¿Cómo hacer que un método se aplica a un conjunto de ActiveRecord objetos

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

¿Cómo puede Defino el método para que esté estructurado de esa manera?

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

Este es el código del modelo actual:

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 

Respuesta

0

Se puede crear un método en la clase de mensaje que ver algo en la línea de ...

En su controlador ... .

@csv_file = Message.send_all_to_csv 

En su modelo ...

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 
0

se podría definir el método directamente en el objeto messages sí mismo, pero si lo hace, el método sólo estarían disponibles para esa instancia específica:

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 

Entonces se le puede llamar así:

messages.to_csv 

soy un novato Ruby, así que no estoy seguro si esto es idiomático Rubí o no: es decir, no estoy seguro de qué tan común o aceptado que es definir nuevos métodos directamente en instancias de objeto, Solo sé que es posible ;-)

2

FasterCSV parchea la clase Array y le agrega un método 'to_csv', pero no hace lo que desea. Puede sobrescribirlo usted mismo haciendo algo como:

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

O algo así, pero eso es un poco asqueroso.

Honestamente, tiene más sentido la forma en que lo ha hecho como método de clase en su modelo.

6

Lo siguiente llamará a tokcs en todas las instancias incluidas en la matriz de mensajes.

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

En Rails, en Ruby 1.9 o con el símbolo # to_proc disponible a través de otros medios, también se puede acortarlo a:

csv = messages.map(&:to_csv) 

La forma más larga es útil cuando se quiere hacer una más compleja operación:

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

símbolo # to_proc también está disponible en rubí 1.8.7 – artemave

3

poner esto en un archivo en lib/. Yo recomendaría llamar algo así como 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 

Después de eso, voy a config/environment.rb y poner require 'base_ext' en la parte inferior del archivo para incluir la nueva extensión.Al reiniciar su servidor, debe tener acceso a un método to_csv en todas las clases de modelos y, cuando lo pase, una matriz de objetos debería generar un buen formato CSV para usted.

+0

config/environment.rb no existe en los nuevos carriles, ¿verdad? Además, el nombre de archivo debe ser _base_ext.rb_ o base_ext.rb? –

+0

Sí, sí existe. He arreglado el nombre del archivo ahora. –

0

Si se aísla a un modelo AR Yo añadiría un método de instancia to_custom_csv_array

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

entonces anular encontrar en la clase

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

y en CustomToCSV definir el to_custom_csv para generar el 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 

Esto es de memoria, pero debería funcionar.

0

Sé que es una pregunta muy antigua pero de todos modos pensé en proporcionar una respuesta. cheque el blog http://blog.zahiduzzaman.com/2013/07/adding-tocsv-method-to-active-record.html sólo otra forma de lograr esto

+0

El enlace que proporcionó está roto en 2015. – Chris

+0

disculpe por no ver esto, pero todavía puedo acceder al enlace. ¿Puedes decir si puedes ver el enlace – Zahiduzzaman

+0

¡Puedo verlo ahora! ... pero me pregunto si es por eso que sería bueno tener la respuesta en línea aquí. – Chris

Cuestiones relacionadas