Ruby on Rails: pasar un valor devuelto de un método a has_attached_file. ¿Me sale mal la syntax de Ruby?

Estoy escribiendo mi primera aplicación RoR y actualmente estoy trabajando para permitir que los usuarios carguen imágenes. Estoy usando Paperclip para este propósito. Uno de los pasos consiste en agregar has_attached_file a mi modelo:

 class MyModel ", small: "60x75#>" } #... end 

Si lo hago así, todo funciona sin problemas (o eso parece). Pero también necesitaré acceder a los mismos valores constantes que los enteros en otro lugar, así que he agregado un hash:

 class MyModel ", small: "60x75#>" } def picture_sizes { large: {width: 120, height: 150}, small: {width: 60, height: 75} } end #... end 

Esto crea una fea redundancia. Así que pensé en escribir un método que genere el primer hash del segundo, como este

 class MyModel " end return result end #... end 

Pero esto levanta un error:

 undefined local variable or method `picture_sizes_as_strings' for # 

¿Qué estoy haciendo mal?

El problema es que está intentando usar un método de instancia picture_sizes_as_strings en una statement ( has_attached_image ) que se ejecuta en el nivel de clase. Es la diferencia entre llamar

 MyModel.picture_sizes_as_strings 

y

 MyModel.first.picture_sizes_as_strings 

En el primer caso, nos referimos a un método de clase (un método en la clase MyModel) y en el segundo caso nos referimos a un método de instancia (un método en el objeto my_model individual).

Entonces, primero que todo, tienes que cambiar los métodos a los métodos de clase prefijando sus nombres con self. , asi que:

 def self.picture_sizes { large: {width: 120, height: 150}, small: {width: 60, height: 75} } end 

Ahora, eso no soluciona completamente su problema todavía, porque has_attached_image se procesa cuando el modelo es analizado por primera vez por ruby. Eso significa que intentará ejecutar has_attached_image antes de definir self.picture_sizes por lo que aún dirá undefined method .

Puedes arreglar esto poniendo self.picture_sizes antes de la statement has_attached_file pero eso es bastante feo. También podría poner los datos en una constante, pero eso tiene sus propios problemas.

Sinceramente, no hay una manera realmente bonita de arreglar esto. Si fuera yo, probablemente revertiría todo el proceso, definiría los estilos como normales y luego usaría un método para convertir las cadenas en números enteros, algo como esto:

 class MyModel < ActiveRecord::Base has_attached_file :picture, styles: { large: "120x150#>", small: "60x75#>" } def numeric_sizes style # First find the requested style from Paperclip::Attachment style = self.picture.styles.detect { |s| s.first == style.to_sym } # You can consolidate the following into one line, I will split them for ease of reading # First strip all superfluous characters, we just need the numerics and the 'x' to split them sizes = style.geometry.gsub(/[^0-9x]/,'') # Next split the two numbers across the 'x' sizes = sizes.split('x') # Finally convert them to actual integer numbers sizes = sizes.map(&:to_i) end end 

Luego puede llamar a MyModel.first.numeric_sizes(:medium) para averiguar los tamaños de un estilo específico, devuelto como una matriz. Por supuesto, también puedes cambiarlos a un hash o al formato que necesites.

el has_attached_file se evalúa en tiempo de ejecución. Ha definido un método de instancia, pero no está llamando al método desde un contexto de instancia.

Tratar:

 def self.picture_sizes_as_strings # code here end 

Asegúrese de definir el otro método con self. además

y entonces:

 has_attached_file :picture, :styles => picture_sizes_as_strings 

Deberia trabajar.