2009-10-07 12 views
11

Extiendo una clase (que está en un complemento) incluyendo un módulo, esto se hace en un inicializador.¿Cómo extender una clase desde un inicializador y hacer que se vuelva a cargar en el entorno de desarrollo?

require 'qwerty/core/user' 
User.send :include, Qwerty::Core::Extensions::User 

Sin embargo, en el desarrollo antes de cada petición (y después de recarga! Que se llama en la consola) todos los modelos se vuelven a cargar, pero debido a que los inicializadores no se ejecutan de nuevo el módulo no está incluido. Dejando un modelo con 'partes faltantes'.

Como el modelo está en un complemento, no parece aconsejable incluir el código directamente en la clase, que sería el enfoque habitual.

Por ahora simplemente he agregado un before_filter que incluye el módulo si está en el entorno de desarrollo. Pero tengo copiar/pegar y tener código duplicado en el controlador de inicializador y aplicación.

# Class extensions in initalizers are over-writtern each request 
    def development_loading 
    if RAILS_ENV == 'development'  
     User.send :include, Qwerty::Core::Extensions::User 
    end 
    end 

¿Hay una manera mejor?

Como nota al margen el plugin es mío, así que podría agregar código a ella, pero las extensiones realizadas en el módulo no puede estar siempre presente ...

Respuesta

11

environment.rb

config.to_prepare do 
    User.send :include, Qwerty::Core::Extensions::User 
end 

El código es el bloque se ejecuta antes de cada solicitud en modo de desarrollo y una vez en modo de producción.

+1

Esto funcionó para mí, pero en application.rb (rieles 3.0.20), no environment.rb – tekniklr

+0

Esto funciona perfectamente en rieles 4 si agrega esto a engine.rb en el motor de rieles. ¡Gracias! –

0

¿Por qué usan inicializadores para incluir la funcionalidad?

intente lo siguiente en su lugar:

require 'qwerty/core/user' 
class User < ActiveRecord::Base 
    include Qwerty::Core::Extensions::User 
    # bla bla 
end 
+0

Porque solo quiere que el código esté incluido en el modo de desarrollo. – SFEley

+0

Porque el modelo está en un complemento, que si bien es un complemento que estoy desarrollando, lo estoy tratando como un complemento de terceros, así que no quiero tocar el código en él. Entonces, debo extender esas clases desde el exterior. – Kris

1

Al principio iba a aconsejar algo acerca de la adición de un directorio de 'desarrollo' a la parte delantera de su trayectoria de carga en el modo de desarrollo, para que sus revisiones siempre conseguirían recargado primero ... Pero luego se me ocurrió que dijiste algo confuso.

El modelo que intentas extender. Está en un plugin ? Los complementos no son supuestos que se volverán a cargar de forma predeterminada en el modo de desarrollo, a menos que la aplicación indique explícitamente que deberían en su configuración estableciendo Config.reload_plugins? en falso.

Pero si, por alguna razón, su plugin está recargando de todos modos y que No quiere, se puede poner esto en de init.rb su plugin para decir explícitamente que no debe recargar:

Dependencies.load_once_paths << lib_path 

Consulte la documentación de carriles en la clase de configuración para más detalles: http://api.rubyonrails.org/classes/Rails/Configuration.html#M002536

+0

Sí, tengo reload_plugins? establecido en verdadero porque estoy desarrollando activamente el complemento. Quiero encontrar una manera de extender los modelos en el complemento desde la aplicación Rails (es decir, sin tocar el código del complemento). Un poco confuso, sí! En mi init.rb tengo: if RAILS_ENV == 'development' ActiveSupport :: Dependencies.load_once_paths.reject! {| X | x = ~ /^#{Regexp.escape(File.dirname(__FILE__))}/} final – Kris

+0

Creo que mi problema es porque estoy tratando de hacer dos cosas a la vez: trabajar en un complemento (volver a cargarlo en cada solicitud) y extender el complemento desde la aplicación Rails. Un poco atrapa 22 ... – Kris

+0

¿Por qué? ¿Por qué darse todas estas restricciones? No desea agregar código de desarrollo al complemento, no desea cargarlo solo una vez y desea invertir el _idea_ de un complemento ampliando su complemento desde su aplicación (que es filosóficamente al revés). ¿Qué ganas en todos estos casos especiales? ¿Agregar algunas condiciones 'if RAILS_ENV == 'development'' en tu complemento va a romper algo? Siempre podría volver a sacarlo más tarde, o poner las extensiones en archivos que solo viven en una rama especial de Git. Deja de luchar contra el río. Ir con el flujo. Deje que Rails sea Rails. Consíguelo hecho. – SFEley

3

solución ligeramente más elegante que la aceptada ya que se puede poner en un inicializador:

require 'dispatcher' 

Dispatcher.to_prepare do 
    # stuff that needs to happen once per initialization 
end 
6

En Rails 3.x puede configurar un bloque a ejecutar cada vez que vuelve a cargar suceden (en el modo de desarrollo, o cuando config.cache_classes = false).Esto iría en un inicializador:

ActionDispatch::Callbacks.to_prepare do 
    # configure stuff or initialize 
end 
Cuestiones relacionadas