2012-07-17 12 views
6

En primer lugar, estoy siguiendo la práctica encontrado aquí por preocupaciones carriles (gran idea!): https://gist.github.com/1014971Rails 3 Módulos preocupación por modelos

estoy recibiendo un error sin embargo:

undefined method `search' for #<Class:0x5c25ea0> 
app/controllers/accessories_controller.rb:6:in `index' 

I DO tengo mi directorio/app/models/concerns/cargado en /config/application.rb. Entonces los módulos de "preocupación" ESTÁN siendo cargados. Solo quería señalar eso.

Aquí está mi código:

/app/models/concerns/searchable.rb

module Searchable 
    extend ActiveSupport::Concern 

    # Add a "search" scope to the models 
    def self.search (search) 
    if search 
     where('name LIKE ?', "%#{search}%") 
    else 
     scoped 
    end 
    end 
end 

/app/models/accessory.rb

class Accessory < ActiveRecord::Base 
    include Searchable 

    ... 
end 

/app/controllers/accessories_controller.rb

class AccessoriesController < ApplicationController 

    def index 
    @accessories = Accessory.search(params[:search]) 

    ... 
    end 

end 

Respuesta

8

Bueno, con un poco más jugando descubrí cuál es el problema.

Cuando desee modificar directamente el Modelo desde dentro del Módulo (preocupación), debe ajustar la funcionalidad dentro de un bloque incluido.

he cambiado mi preocupación módulo a lo siguiente:

module Searchable 
     extend ActiveSupport::Concern 

     included do 
      # Add a "search" scope to the models 
      def self.search (search) 
       if search 
        where('name LIKE ?', "%#{search}%") 
       else 
        scoped 
       end 
      end 
     end 

    end 

Eso es todo! ¡Espero que esto ayude a alguien más con la misma pregunta!

+0

¡Qué bueno que lo haya descubierto usted mismo! Un par de consejos más: No debe poner un espacio entre la definición del método y los argumentos para el método. Simplemente no se hace así en el mundo de Ruby. Ahora con respecto al método 'incluido', lo que hará es evaluar ese bloque completo dentro del contexto de la clase. Si desea definir métodos para la clase, recomendaría simplemente definir los métodos en el módulo en sí, en lugar de incluirlos también dentro del bloque incluido. –

+0

Gracias por el recordatorio sobre el nombre del método. Mis propias "mejores prácticas" a veces se deslizan aquí y allá de vez en cuando. Entiendo lo que dices sobre el bloque 'incluido'. Si estuviera definiendo un método que no es propio, lo pondría fuera del bloque. ¡Gracias! –

8

Eso es una solución decente, pero no es realmente la mejor solución . Cuando se construye un módulo sobre ActiveSupport::Concern se puede envolver un módulo llamado ClassMethods dentro de su preocupación y cualquier módulo que incluye su preocupación se extenderá automáticamente con el módulo ClassMethods.

Una mejor solución, entonces, sería:

module Searchable 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def search(search) 
     if search 
     where('name LIKE ?', "%#{search}%") 
     else 
     scoped 
     end 
    end 
    end 
end 

Eso (OMI) expresa con mayor claridad su intención: la colocación de un método de nivel de clase en la clase.

Mientras que su enfoque funciona, el método included es mejor utilizado cuando se necesita para invocar métodos de la clase que llama. Por ejemplo, puede insistir en que sus objetos Searchable tengan un atributo name db-backed como se muestra a continuación. El método included está agregando el validador presence a la clase llamante, y los métodos que está utilizando para extender la clase están claramente separados.

module Searchable 
    extend ActiveSupport::Concern 

    def self.included(base) 
    base.send :validates_presence_of, :name 
    end 

    module ClassMethods 
    def search(search) 
     if search 
     where('name LIKE ?', "%#{search}%") 
     else 
     scoped 
     end 
    end 
    end 
end 
2

Como AndyV points out, la solución correcta es la siguiente:

module Searchable 
    extend ActiveSupport::Concern 

    module ClassMethods 
    def search(search) 
     if search 
     where('name LIKE ?', "%#{search}%") 
     else 
     scoped 
     end 
    end 
    end 
end 

Y no definir self.search en el bloque included como lo están haciendo en su solución, que es más detallado y menos explícito.

Pero no estoy de acuerdo con AndyV en el uso de self.included. Si usa ActiveSupport::Concern, es tener el azúcar sintáctico de bloque included, por lo que debería usarlo. Solo confío en self.included cuando importa el orden de los métodos que llamo o los métodos que defino.

Cuestiones relacionadas