2011-05-12 11 views
8

Estoy usando clip para cargar mis documentos a Amazon S3. Me gustaría crear automáticamente un depósito con la ID de mis proyectos cuando cargue un nuevo documento.clips de rieles S3 con nombre de cubo dinámico

Por lo tanto, en mi controlador, tengo esto:

def new 
    @pmdocument = Pmdocument.new 
    @pmdocument.projectmilestone_id=params[:projectmilestone_id] 

donde projectmilestone_id es la foreign_key a mi proyecto (para ser utilizado como mi nombre de depósito)

Mi modelo es la siguiente:

class Pmdocument < ActiveRecord::Base 
    belongs_to :projectmilestone 
    attr_accessible :id, :name, :description, :projectmilestone_id, :pmdoc, :projectmilestone_attributes 
    attr_protected :pmdoc_content_type, :pmdoc_size 
    accepts_nested_attributes_for :projectmilestone, :allow_destroy => false 
    has_attached_file :pmdoc, 
    :storage => :s3, 
    :bucket => self.projectmilestone_id.to_s, 
    :s3_credentials => File.join(Rails.root, 'config', 's3.yml') 

Cuando me carga la página, me sale este error: método no definido `projectmilestone_id' para #

Comprobé mi controlador y el campo projectmilestone_id está cargado correctamente allí.

Traté de cambiar la línea del cucharón a :bucket => self.name y luego el error se ha ido.

El modelo funciona bien porque projectmilestone_id está almacenado correctamente en el archivo db.

Supongo que podría estar vinculado a los atributos accesibles, pero parece estar bien también.

¿Qué pasa? ¡¡¡Muchas gracias!!!


Realmente no conseguirlo:

decidí no cambiar mi cubo más (mala idea de todos modos como el nombre tiene que ser único para todos S3), pero para cambiar mi camino en su lugar.

Este es el código:

:path => proc { |attachment| "#{attachment.istance.projectname}/:attachment/:id/:basename.:extension" }, 

No se crea la primera carpeta con mi nombre de proyecto. Si reemplazo projectname por nombre, o incluso descripción (otro campo de documentos de pm), funciona, pero no con projectname. Por supuesto, verifiqué que el nombre del proyecto esté correctamente poblado. La razón está en otra parte.

¿Alguna pista?

Respuesta

10

El método has_attached_file se ejecuta en el contexto de la clase (cuando se carga el archivo), no en el contexto de una instancia de registro donde podría usar atributos y otro método de instancia. self.name funciona de hecho, pero devuelve el nombre de la clase ("Pmdocument"), no el nombre de un registro.

Pero Paperclip tiene la amabilidad de permitir lo que quieras. El documentation on the S3 storage dice:

You can define the bucket as a Proc if you want to determine it’s name at runtime. Paperclip will call that Proc with attachment as the only argument.

En su caso sería algo como esto:

has_attached_file :pmdoc, 
    :storage => :s3, 
    :bucket => proc { |attachment| attachment.instance.projectmilestone_id.to_s }, 
    :s3_credentials => File.join(Rails.root, 'config', 's3.yml') 

Ahora se pasa un Proc a has_attached_file. El contenido del bloque no se evalúa mientras se carga su clase, pero más tarde cuando es necesario. Paperclip llama al bloque con el attachment como argumento y usa el valor devuelto como nombre del depósito.

Editar:

Por desgracia, este bloque se ejecuta cuando se asigna el archivo, no cuando el registro se guarda. Por lo tanto, es posible que no se hayan establecido todos sus atributos (el orden de la asignación de los atributos cuando lo hace Pmdocument.new(params[:pmdocument]) es indeterminado). Me gustaría clip para trabajar de otra manera, pero mientras tanto veo 2 opciones:

Puede eliminar el archivo de los parametros en el controlador y configurarlo cuando todo lo demás está listo:

pmdoc = params[:pmdocument].delete(:pmdoc) 
@pmdocument = Pmdocument.new(params[:pmdocument]) 
@pmdocument.pmdoc = pmdoc 

O puede retrasar el postprocesamiento de Paperclip deshabilitándolo con before_post_process (consulte la sección Eventos del README) y ejecutarlo en un after_save callback.

+0

Gracias por esta muy útil explicación. Soy nuevo en los rieles y en la programación de OO y aún no he entendido todo. Hice lo que dices arriba, pero aparentemente, no puedo crear un cubo con un dígito como nombre. Así que traté de usar mis relaciones para volver al nombre del proyecto: proc {| attachment | attachment.instance.projectmilestone.projectcapstone.project.name.to_s} pero tengo otro error: "undefined method' projectcapstone 'for nil: NilClass ". Esto es extraño porque mi clase no parece ser nula ya que funciona sin pasar por las relaciones. ¿Qué pasa esta vez? ¡¡¡Gracias!!! – ndemoreau

+0

El bloque se puede ejecutar cuando se asigna el archivo (tal vez una línea como 'pmdocument.pmdoc = params [...]' o 'pmdocument.update_attributes (...)'). Asegúrese de que su objeto tenga un 'projectcapstone' válido antes de esta asignación. –

+0

El hecho de que las opciones de configuración en realidad * se * puedan dar un lambda/proc con un parámetro (el archivo adjunto) me salvó la vida. ¡Muchas gracias! <3 – dimitarvp

Cuestiones relacionadas