2012-03-15 28 views
10

Estoy tratando de abstraer parte de la lógica necesaria para recortar imágenes en un módulo para que no estropee mis modelos. El código se basa en http://railscasts.com/episodes/182-cropping-imagesruby ​​include vs extender

module CroppableImage 
    def croppable_image(*image_names) 
    image_names.each do |image_name| 

     define_method "#{image_name}_sizes" do 
     { :cropped => read_attribute("#{image_name}_size").to_s, :large => "800x800>" } 
     end 

     define_method "#{image_name}_geometry" do |style| 
     style ||= :original 
     @geometry ||= {} 
     @geometry[style] ||= Paperclip::Geometry.from_file(eval "#{image_name}.path(style)") 
     end 

     define_method "#{image_name}_aspect_ratio" do 
     width, height = read_attribute("#{image_name}_size").split("x") 
     width.to_f/height.to_f 
     end 

     private 

     define_method "reprocess_#{image_name}" do 
      eval "#{image_name}.reprocess!" 
     end 

    end 
    end 

end 

Para incluir esto en mi modelo parece que tengo que usar extender. Pensé que extender era para incluir métodos de clase. Soy de origen java. Pensé en usar extender el método estático creado básicamente en la clase.

class Website < ActiveRecord::Base 
    extend CroppableImage 
    croppable_image :logo, :footer_image 

- esto funciona

Parece entonces que lo que realmente estoy queriendo es crear métodos de instancia.

class Website < ActiveRecord::Base 
    include CroppableImage 
    croppable_image :logo, :footer_image 

- Esto arroja el error "método no definido` croppable_image' para #"

Puede alguien por favor explicar qué se está encendiendo y si debería estar usando incluyen o extender en este caso. Gracias chicos

+1

'extend' añade los métodos como métodos de clase, mientras que' include' añade los métodos como métodos de instancia. – zeacuss

Respuesta

13

extend M internamente es similar a class << self; include M; end - extend incluye módulo en la clase singleton de un objeto (y hace que los métodos de instancia del módulo que se va a métodos simples de una clase se amplía).

En su caso se llaman croppable_imageen el contexto de una definición de clase y por lo tanto croppable_image debe haber un método de instancia de una clase Class o un método de Singleton Website clase.

Esto es por eso que debe extender Website clase con un módulo CroppableImage utilizando extienden CroppableImage - añade método de instancia croppable_image como método de Singleton Website clase.

+0

Creo que finalmente lo tengo. croppable_image es un método de clase, pero los métodos que se definen con define_method se convierten en métodos de instancia. Acabo de leer http://stackoverflow.com/questions/302789/can-i-define-method-in-rails-models y ahora todo tiene mucho más sentido. Gracias por su ayuda – Nick

+0

@Nick, Sí, 'define_method' se ejecuta en la clase' Sitio web' y 'define_method' agrega * métodos de instancia * de la clase' Sitio web'. –

7

puede usar ambas lógicas juntas. Ruby tiene devoluciones de llamada para extender e incluir Ejemplo de utilización de devolución de llamada incluido

module CroppableImage 
    def self.included(base) 
    base.extend(ClassMethods) 
    end 

    module ClassMethods 
    def bar 
     puts 'class method' 
    end 
    end 

    def foo 
    puts 'instance method' 
    end 
end 
+0

una forma elegante de hacerlo;) – Aghyad