¿La mejor manera de cargar el módulo / clase desde la carpeta lib en Rails 3?

273

Dado que la última versión de Rails 3 ya no es la carga automática de módulos y clases desde lib, ¿cuál sería la mejor manera de cargarlos?

De github:

A few changes were done in this commit:

Do not autoload code in *lib* for applications (now you need to explicitly 
require them). This makes an application behave closer to an engine 
(code in lib is still autoloaded for plugins);
Vincent
fuente

Respuestas:

251

A partir de Rails 2.3.9 , hay una configuración en la config/application.rbque puede especificar directorios que contienen archivos que desea cargar automáticamente.

Desde application.rb:

# Custom directories with classes and modules you want to be autoloadable.
# config.autoload_paths += %W(#{config.root}/extras)
Slobodan Kovacevic
fuente
77
Tenga en cuenta la respuesta de @ agradecido también si desea cargar automáticamente el subárbol completo de app/lib.
Tom Harrison el
199
# Autoload lib/ folder including all subdirectories
config.autoload_paths += Dir["#{config.root}/lib/**/"]

Fuente: Rails 3 Sugerencia rápida: directorio lib de carga automática que incluye todos los subdirectorios, evite la carga diferida

Tenga en cuenta que los archivos contenidos en la carpeta lib solo se cargan cuando se inicia el servidor. Si desea la comodidad de volver a cargar automáticamente esos archivos, lea: Rails 3 Sugerencia rápida: recargue automáticamente las carpetas lib en modo de desarrollo . Tenga en cuenta que esto no está destinado a un entorno de producción, ya que la recarga permanente ralentiza la máquina.

agradecido
fuente
Los enlaces están muertos
Besi
84

La magia de la carga automática

Creo que la opción que controla las carpetas desde las que se realiza la carga automática se ha cubierto suficientemente en otras respuestas. Sin embargo, en caso de que alguien más tenga problemas cargándose aunque hayan modificado sus rutas de carga automática según sea necesario, esta respuesta intenta explicar cuál es la magia detrás de esta carga automática.

Entonces, cuando se trata de cargar cosas desde subdirectorios, hay una trampa o una convención que debes tener en cuenta. A veces, la magia Ruby / Rails (esta vez principalmente Rails) puede dificultar la comprensión de por qué sucede algo. Cualquier módulo declarado en las rutas de carga automática solo se cargará si el nombre del módulo corresponde al nombre del directorio principal. Entonces, en caso de que intentes poner lib/my_stuff/bar.rbalgo como:

module Foo
  class Bar
  end
end

No se cargará automáticamente. Por otra parte, si cambia el nombre del directorio padre de fooalojamiento tanto en el módulo de ruta: lib/foo/bar.rb. Estará allí para ti. Otra opción es nombrar el archivo que desea cargar automáticamente con el nombre del módulo. Obviamente, solo puede haber un archivo con ese nombre. En caso de que necesite dividir sus cosas en muchos archivos, por supuesto, puede usar ese archivo para requerir otros archivos, pero no lo recomiendo, porque cuando esté en modo de desarrollo y modifique esos otros archivos, Rails no podrá automaticamente Vuelva a cargarlos para usted. Pero si realmente lo desea, podría tener un archivo con el nombre del módulo que luego especifique los archivos reales necesarios para usar el módulo. Por lo tanto, podría tener dos archivos: lib/my_stuff/bar.rby lib/my_stuff/foo.rbel primero es el mismo que el anterior y el último contiene una sola línea:require "bar"y eso funcionaría igual

PD: Me siento obligado a agregar una cosa más importante. Últimamente, cada vez que quiero tener algo en el directorio lib que necesita cargarse automáticamente, tiendo a empezar a pensar que si esto es algo que realmente estoy desarrollando específicamente para este proyecto (que suele ser, algún día podría se convierta en un fragmento de código "estático" utilizado en muchos proyectos o en un submódulo git, etc. en cuyo caso definitivamente debería estar en la carpeta lib), entonces tal vez su lugar no esté en la carpeta lib en absoluto. Quizás debería estar en una subcarpeta debajo de la carpeta de la aplicación · Tengo la sensación de que esta es la nueva forma de hacer las cosas. Obviamente, la misma magia está en el trabajo en cualquier lugar en el que cargue automáticamente los caminos en los que coloque sus cosas, por lo que es bueno para estas cosas. De todos modos, esto es solo mis pensamientos sobre el tema. Eres libre de estar en desacuerdo. :)


ACTUALIZACIÓN: Sobre el tipo de magia ...

Como severin señaló en su comentario, el núcleo "mecanismo de carga automática de un módulo" es parte de Ruby, pero las cosas de las rutas de carga automática no lo son. No necesitas rieles para hacerautoload :Foo, File.join(Rails.root, "lib", "my_stuff", "bar"). Y cuando intentes hacer referencia al módulo Foo por primera vez, se cargará por ti. Sin embargo, lo que hace Rails es que nos brinda una forma de intentar cargar cosas automáticamente desde carpetas registradas y esto se ha implementado de tal manera que debe asumir algo sobre las convenciones de nomenclatura. Si no se hubiera implementado así, cada vez que haga referencia a algo que no está cargado actualmente, tendría que revisar todos los archivos en todas las carpetas de carga automática y verificar si alguno de ellos contiene lo que estaba tratando de hacer referencia. Esto a su vez derrotaría la idea de la carga automática y la recarga automática. Sin embargo, con estas convenciones en su lugar, puede deducir del módulo / clase su intento de cargar donde se podría definir y simplemente cargar eso.

Timo
fuente
1
¿Por qué es esta magia Ruby? Ruby solo proporciona la función de carga automática del Módulo # que puede usar para ordenar un archivo que se carga al acceder a una constante (indefinida) (consulte ruby-doc.org/core-1.9.3/Module.html#method-i-autoload ). En mi opinión, la correspondencia de los nombres de módulos / clases con los directorios / archivos se realiza en Rails / ActiveSupport (por ejemplo, aquí: github.com/rails/rails/blob/… ). ¿Me equivoco?
severin
Sí, creo que tienes razón. Fui demasiado apresurado para "corregir" mi respuesta original cuando Zabba señaló su "defecto". Permítanme actualizar mi respuesta un poco más para aclarar este problema.
Timo
1
Pasé media hora más o menos bromeando. Necesitaba (quería) cargar automáticamente Sprockets :: JSRender :: Processor. La ruta para eso se puede encontrar entrando en la consola de rails y haciendo "Sprockets :: JSRender :: Processor" .underscore y rechazando que sea "sprockets / js_render / procesador" (con .rb agregado) HTH alguien.
pedz
Acabas de salvar mi cordura. ~ profundo suspiro de alivio ~ muchas gracias por compartir :)
Brenden
Gracias por este comentario tan útil. No entendí por qué algunos módulos se comportaban como lo hicieron hasta que leí tu comentario. Bendiciones para ti!
mjnissim
41

Advertencia: si desea cargar el 'parche de mono' o 'clase abierta' desde su carpeta 'lib', ¡no use el enfoque de 'carga automática' !

  • Enfoque " config.autoload_paths ": solo funciona si está cargando una clase que se definió solo en UN lugar. Si alguna clase ya se ha definido en otro lugar, este enfoque no puede volver a cargarla.

  • "Enfoque config / initializer / load_rb_file.rb ": ¡siempre funciona! cualquiera que sea la clase objetivo es una nueva clase o una "clase abierta" o "parche de mono" para la clase existente, ¡siempre funciona!

Para obtener más detalles, consulte: https://stackoverflow.com/a/6797707/445908

Siwei Shen 申思维
fuente
66
Esta es una distinción crítica para entender. Gracias por esto.
Tyler Collier
28

Muy similar, pero creo que esto es un poco más elegante:

config.autoload_paths += Dir["#{config.root}/lib", "#{config.root}/lib/**/"]
Brian Armstrong
fuente
18

En mi caso, estaba tratando de cargar un archivo directamente bajo el directorio lib.

Dentro de application.rb ...

require '/lib/this_file.rb' 

no funcionaba, incluso en la consola y luego cuando intenté

require './lib/this_file.rb' 

y rails carga el archivo perfectamente.

Todavía soy bastante novato y no estoy seguro de por qué funciona, pero funciona. Si alguien quisiera explicármelo, lo agradecería: espero que esto ayude a alguien de cualquier manera.

Nick Res
fuente
2
Esto se debe a que ./lib/this_file.rb busca en el directorio actual (en la consola de Rails, esa sería la raíz de Rails), y /lib/this_file.rb busca eso como una ruta absoluta. Ejemplo: ./lib/this_file.rb = /var/www/myrailsapp/lib/this_file.rb, /lib/this_file.rb = /lib/this_file.rb
Jason
7

Yo tuve el mismo problema. Así es como lo resolví. La solución carga el directorio lib y todos los subdirectorios (no solo el directo). Por supuesto, puede usar esto para todos los directorios.

# application.rb
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
hjuskewycz
fuente
55
Esto tiene el efecto secundario desagradable de golpear totalmente las convenciones de espacios de nombres de Rails. Si lib / bar / foo.rb define Bar :: Foo aparece antes de lib / foo.rb que define Foo en la búsqueda de carga automática, entonces obtendrá errores confusos como Expected lib/bar/foo.rb to define constant Foosi intenta cargar lib / foo.rb haciendo referencia al Foo constante.
Jacob
5

config.autoload_paths no funciona para mí. Lo resuelvo de otra manera

Ruby on rails 3 no recarga automáticamente el código (carga automática) desde la carpeta / lib. Lo resuelvo poniendo dentroApplicationController

Dir["lib/**/*.rb"].each do |path|
  require_dependency path
end 
msa.im
fuente
4

Si solo ciertos archivos necesitan acceso a los módulos en lib, simplemente agregue una declaración require a los archivos que lo necesitan. Por ejemplo, si un modelo necesita acceder a un módulo, agregue:

require 'mymodule'

en la parte superior del archivo model.rb.

Mike Fischer
fuente
50
No debe usar requiredentro de una aplicación de rieles, ya que impide ActiveSupport::Dependencies[des] cargar ese código correctamente. En su lugar, debe usar config.autoload_pathscomo la respuesta anterior y luego incluir / extender según sea necesario.
ben_h
13
Gracias @ Mike, iba a hacer lo que hiciste, fue bueno ver una explicación de por qué es malo, gracias por no eliminar la respuesta.
pupeno
¿Qué hay de incluir 'mymodule' si solo quieres cargar un módulo?
Mike
1
@ben_h ¿No deberías requirede ninguna parte de una aplicación Rails? En una tarea de rastrillo, actualmente estoy require-ing y include-ing un módulo que vive en lib/. ¿No debería estar haciendo eso?
Dennis
@ben_h Mi búsqueda revela que es común a requiresu lib/código (por ejemplo, esta publicación de blog , esta respuesta SO ). Todavía no estoy seguro de todo el asunto. ¿Puedes dar más evidencia detrás del reclamo por no usar require?
Dennis
2

Deletree el nombre de archivo correctamente.

Seriamente. Luché con una clase durante una hora porque la clase era Governance :: ArchitectureBoard y el archivo estaba en lib / gobierno / architecture_baord.rb (O y A transpuestos en "tablero")

Parece obvio en retrospectiva, pero fue el demonio quien lo rastreó. Si la clase no está definida en el archivo en el que Rails espera que esté basada en mezclar el nombre de la clase, simplemente no la encontrará.

David Hempy
fuente
2

En fecha Rails 5, se recomienda poner la carpeta lib en el directorio de aplicaciones o en lugar de crear otros espacios de nombres significativos para la carpeta como services, presenters,features etc., y ponerlo en el directorio de aplicaciones para la carga automática de los carriles.

Compruebe también este enlace de discusión de GitHub .

Ashik Salman
fuente