2010-07-19 12 views
55

Estoy creando un nuevo motor para una aplicación de rails 3. Como puede adivinar, este motor está en el directorio lib de mi aplicación.Ruby on Rails 3 - Recargar el directorio lib para cada solicitud

Sin embargo, tengo algunos problemas para desarrollarlo. De hecho, necesito reiniciar mi servidor cada vez que cambio algo en el motor.

¿Hay alguna manera de evitar esto?

¿Puedo obligar a los carriles para recargar completamente el directorio lib o un archivo específico y sus requisitos para cada solicitud?

Gracias por su ayuda :)

Respuesta

30

TL; DR

  • poner esto en config/aplicación.rb

    config.eager_load_paths += ["#{Rails.root}/lib"]

  • eliminar require declaraciones para sus lib archivos

Go!


Déjame explicarte en detalle.

No sé por qué se acepta esta respuesta, ya que no ayuda con cargando la carpeta lib en cada solicitud. Primero pensé que funciona para Rails 2, pero la pregunta claramente establece que fue para Rails 3 y que la fecha de lanzamiento de 3.0.0 es anterior a la fecha de la respuesta.

Otras respuestas parecen demasiado complicadas o no proporcionan una solución real.

decidí investigar un poco las cosas, porque me molestaba e incluso he descubierto que la gente tiene una solución para esto y se trata de guardar archivos lib dentro app/models en el desarrollo y luego moverlo a /lib cuando haya terminado. Podemos hacerlo mejor, ¿verdad?


Mi solución se prueba contra:

  • Rails 3.0.20
  • Rails 3.1.12
  • Rieles 3.2.13
  • Rails 4.0.0.rc1

Pon esto en tu config/application.rb:

# in config/application.rb 
config.eager_load_paths += ["#{Rails.root}/lib}"] 

Eso es todo! ™

Asegúrese de poner aquí ya que no funciona si lo pones en config/environments/development.rb, por ejemplo.

Asegúrese de eliminar todas las declaraciones require para su código /lib ya que las declaraciones require también harán que esta solución no funcione.


Este código requiere implícitamente su código, por lo que si lo hace comprobaciones del entorno (que son innecesarios) y en lugar del código anterior, usted decide escribir algo como esto:

# in config/application.rb 
config.eager_load_paths += ["#{Rails.root}/lib"] if Rails.env.development? 

debe ver en las antiguas declaraciones require, ya que todavía se requieren en todos los entornos sin desarrollo, en este escenario.

Por lo tanto, si aún decide realizar comprobaciones de entorno, asegúrese de realizar comprobaciones inversas para las declaraciones requeridas. De lo contrario, te morderán!

require "beer_creator" unless Rails.env.development? 

Se podría pensar que la escritura párrafo entero de algo que es innecesario también es innecesaria, pero creo que advertir a la gente acerca de algo que es necesario cuando se hace algo innecesario también es necesaria.

Si desea saber más sobre este tema, consulte this little tutorial.

+0

Eso fue hace un tiempo atrás, también puedes usar load sin el eager_load_path.Cree helper que tome la cadena como parámetro y use load si env es dev y requiera si env is prod. Si lo intenta, avísenme si funciona :) –

+0

Parece que no funciona en Rails 3.0.20 con o sin el '}' adicional al final de la cadena. – Ritchie

+0

Esto no funcionó para mí en 3.2.13 - en su lugar, después de agregar el eager_load_paths, todos mis otros archivos (controladores + modelos) dejaron de volver a cargarse entre las solicitudes también! (Vuelve a la normalidad si elimino esa línea.) Bizarro. Finalmente lo conseguí trabajando con esta respuesta: http://stackoverflow.com/a/10954365/1164573 –

3

en Rails 3, aquí está el ingrediente secreto de los archivos lib auto-recargar. El código siguiente es un poco exagerado, por ejemplo, pero es lo que hice para que funcione. Puede cambiar el mensaje en YoYo # gogo y verlo en la pantalla cada carga de página. Elimina el inicializador y permanece igual.

/config/initializers/lib_reload.rb (nuevo archivo)

ActiveSupport::Dependencies.explicitly_unloadable_constants << 'YoYo' 
ActiveSupport::Dependencies.autoload_once_paths.delete(File.expand_path(File.dirname(__FILE__))+'/lib') 

/lib/yo_yo.rb

class YoYo 
    def gogo 
    "OH HAI THERE" 
    end 
end 

/app/controllers/home_controller

require 'yo_yo' 
class HomeController < ApplicationController 
    def index 
    @message = YoYo.new.gogo 
    end 
end 
+1

Creo que en Rails 3 es autoload_once_paths en lugar de load_once_paths –

+1

la mejor respuesta, pero puede acortar File.expand_path (File.dirname (__ FILE __)) + '/ lib' con "# {Rails.root}/lib" y también poner un si Rails.env.development? check – makevoid

13

hay que añadir

config.autoload_paths += %W(#{config.root}/lib) 

a su clase de aplicación en config/application.rb

https://rails.lighthouseapp.com/projects/8994/tickets/5218-rails-3-rc-does-not-autoload-from-lib

+3

Probablemente sea mejor ponerlo en desarrollo.rb –

+15

Esto permite que mis archivos en lib sean * autocargados * (cargados cuando se accede a la constante con el mismo nombre), pero no parece ayudar a que sean * recargados * en cada solicitud/cuando se modifica. Estoy en Rails 3.2.3. –

+2

sí, con este código, los archivos en lib se cargan automáticamente pero no se vuelven a cargar, PERO cuando coloca los archivos en otro lugar, los vuelve a cargar: '$ :. unshift (config.root); config.autoload_paths + =% w (app/models/misc) ' Pienso en mis archivos lib como lógica de negocios, y puse la lógica de negocios también en mis modelos, entonces son mis modelos pero no db-persistido, y es correcto que estén en la aplicación/modelos/misc y no en lib. –

0

nota de que en Rails 3 "load_once_paths" se convierte en "autoload_once_paths."

Además, parece que debería estar vacío a menos que poner algo en él de forma explícita.

46

no pude conseguir cualquiera de los anteriores para trabajar para mí, así que busqué en el código Rieles un poco y se acercó con esto:

Nueva archivo: config/inicializadores/reload_lib.rb

if Rails.env == "development" 
    lib_reloader = ActiveSupport::FileUpdateChecker.new(Dir["lib/**/*"]) do 
    Rails.application.reload_routes! # or do something better here 
    end 

    ActionDispatch::Callbacks.to_prepare do 
    lib_reloader.execute_if_updated 
    end 
end 

Sí, sé que es repugnante pero es un truco. Puede haber una forma mejor de activar una recarga completa, pero esto funciona para mí. Mi caso de uso específico era una aplicación de Rack montada en una ruta de Rails, así que necesitaba volver a cargarla mientras trabajaba en su desarrollo.

Básicamente lo que hace es que comprueba si alguno de los archivos en/lib han cambiado (marca de tiempo modificado) desde el pasado cargada y luego dispara una recarga si cambian.

Podría mencionar también tengo esto en mi config/application.rb

config.autoload_paths += %W(#{config.root}/lib) 
config.autoload_paths += Dir["#{config.root}/lib/**/"] 

Lo cual por defecto hace que todo en mi directorio lib que se carga.

Yays!

+1

Excelente: funciona muy bien si haces subclases de una gema. Lo usé con Grape (por ejemplo, '/ lib/appname/api.rb' comienza con' Appname :: API nfm

+5

@pbhogan La firma de método para FileUpdateChecker # initialize ha cambiado un poco en Rails 3.2.x. Deshágase de "verdadero" y todo debería funcionar bien de nuevo. –

+0

Esto funcionó para mí con la gema de Grape también, gracias @nfm. Sin embargo, tuve que cambiar ligeramente la sintaxis de FileUpdateChecker a: 'ActiveSupport :: FileUpdateChecker.new ([], Dir [" lib/**/* "])' –

20

Como estamos hablando de Rails, la forma más fácil es 'requerir' sus archivos lib/* .rb usando 'require_dependency'. Siempre que el controlador/helper/etc (archivos .rb en la aplicación /) use require_dependency en lugar de solo requerir que se vuelva a cargar, sin la necesidad de hacer nada funky.

Antes de ir por esa pista, la única solución que funcionaba era la de hemju.com, pero realmente no quería tener que hackear ApplicationController para la velocidad de revelado.

+0

Esto funcionó para mí, muy bien –

+0

Esto parece haber funcionado también para mí. Lástima que no puede simplemente funcionar con una simple necesidad ... –

+2

Funciona muy bien con Rails 3.2.6. Esta es la mejor y más limpia respuesta definitivamente. – Georges

0

Además, asegúrese de comentar la siguiente línea en application.rb (además de la solución de @disod), y asegúrese de que el nombre de su módulo sea el mismo que su nombre de archivo (de lo contrario, los rieles no serán capaz de encontrarlo)

#Dir.glob("./lib/*.{rb}").each { |file| require file } # require each file from lib directory 
1

respuesta Actualizado

resumo todos mis resultados en mi blog, es mejor que mire hay:

respuesta Antiguo

busqué una solución para esto también, y (De forma complementaria y también para apuntar en esta dirección otros) esto es lo que encontré.

A partir de Rails3.1, los motores se pueden generar fácilmente a través del comando rails plugin new my_plugin --full. Esto genera el esqueleto para un motor.

--full significa que el motor se "fusionará" directamente en la aplicación incluida, por lo que, por ejemplo, los controladores deben ser accesibles directamente como si estuvieran definidos en la aplicación incluida. Esto le permite, por ejemplo, tener un archivo de ayuda en my_engine/app/helpers/my_helper.rb que se combinará en la aplicación incluida app/helpers/my_helper.rb helper.

Existe otra opción --mountable que crea un espacio de nombres para el motor para que sus controladores, etc. nunca colisionen con los de la aplicación. Esto da como resultado, p. un asistente está en my_engine/app/helpers/my_engine/my_helper.rb que no colisionará con un helper app/helpers/my_helper.rb en su aplicación incluida.

Ahora la parte más interesante:

Dentro de la carpeta del motor generada test, hay una carpeta dummy que mantiene una completa rieles! ¿Para qué es esto?

Cuando desarrolle un motor, sus funcionalidades deben funcionar por sí solas, y también debe probarse completamente por sí mismo. Por lo tanto, es la forma "incorrecta" de desarrollar un motor "dentro" de otra aplicación de Rails (aunque esto intuitivamente a menudo se sentirá bien al extraer funcionalidades existentes de una aplicación de Rails en un motor), y teóricamente tampoco es necesario volver a cargar el motor código con cada solicitud a la aplicación incluida.

La manera "correcta" parece ser esta: desarrolla y prueba tu motor, como si fuera una aplicación completa de Rails con la aplicación dummy. Allí puede hacer todo lo que puede hacer en cualquier aplicación Rails "normal", p. cree controladores, modelos, vistas, etc. que utilicen las funcionalidades que el motor debe proporcionar. También puede iniciar un servidor normalmente usando rails s en su directorio test/dummy y acceder a la aplicación ficticia en localhost:3000, y al ejecutar sus pruebas, la aplicación dummy se utiliza automáticamente para las pruebas de integración. ¡Muy agradable! :-)

Hay que tener cuidado donde poner tus cosas:

  • Cualquier funcionalidad que está destinado a ser utilizado dentro de otra aplicación Rails entra en my_engine/app, mientras que cualquier funcionalidad que sólo se necesita para probar la la funcionalidad del motor entra en test/dummy/app.

A continuación, después se puede cargar fácilmente su motor en Gemfile como éste de su aplicación principal: gem 'my_engine', :path => 'path/to/my_engine' o publicarla en GitHub como una joya.

(Una cosa interesante (y para volver al tema de este tema) es que cuando inicio el servidor del dummy, ¡entonces todos los cambios en el motor parecen estar reflejados en él! Así que de alguna manera parece ser posible incluir un motor dentro de una aplicación de Rails sin guardarlo en caché ...? No sé cómo sucede esto.)

En resumen: un motor proporciona una funcionalidad que puede soportar por sí solo, por lo que también debe desarrollarse y probado por sí mismo. Luego, cuando ha alcanzado un estado estable, puede ser incluido por cualquier otra aplicación que necesite su funcionalidad.

He aquí algunos recursos que encuentro útil:

espero que esta respuesta es útil. Todavía soy muy nuevo en los motores en general, así que si hay información incorrecta, por favor díganme, y la corregiré.

+0

los enlaces no funcionan – brauliobo

3

Aquí está mi versión inspirada en @pbhogan, la respuesta que vuelve a cargar todos los archivos ruby ​​en el directorio rails/lib cuando se cambia alguno de esos archivos.

También silencia las advertencias para evitar mensajes con respecto a las constantes ya inicializadas.

Obras como de rieles 3.2.8

if Rails.env.development? 

    lib_ruby_files = Dir.glob(File.join("lib/**", "*.rb")) 
    lib_reloader ||= ActiveSupport::FileUpdateChecker.new(lib_ruby_files) do 
    lib_ruby_files.each do |lib_file| 
     silence_warnings { require_dependency(lib_file) } 
    end 
    end 

    ActionDispatch::Callbacks.to_prepare do 
    lib_reloader.execute_if_updated 
    end 

end 
0

Trabajado para rieles 3.2.13 para la recarga lib en el interior de la gema de una aplicación:

require_dependency 'the_class'

Y

config.autoload_paths + =% W (# {config.root } /../ fantasía/lib)

1

Añadir a application_controller.rb o su controlador de base:

before_filter :dev_reload if Rails.env.eql? 'development' 

    def dev_reload 
    # add lib files here 
    ["rest_client.rb"].each do |lib_file| 
     ActiveSupport::Dependencies.load_file lib_file 
    end 
    end 

Funcionó para mí.