ruby-on-rails-3 - root_path - routes rails examples
Comportamiento inconsistente de "LoadError" con el espacio de nombres ''lib''/autoloading (5)
Acabamos de crear un nuevo archivo en ''lib'' que ha generado una serie de dolores de cabeza relacionados con errores de carga.
/lib/response_set.rb:
module MyCompany
class ResponseSet < Array
...
end
end
/spec/lib/response_set_spec.rb
require ''spec_helper''
describe MyCompany::ResponseSet do
describe "..." do
...
end
end
La ejecución de esta especificación en Rspec nos da el siguiente error cuando llega al primer ''describe'':
/Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:492:in `load_missing_constant'': Expected /Users/my_stuff/projects/my_project/lib/response_set.rb to define ResponseSet (LoadError)
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/backward_compatibility.rb:20:in `const_missing''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-expectations-2.5.0/lib/rspec/expectations/backward_compatibility.rb:6:in `const_missing''
from /Users/my_stuff/projects/my_project/spec/lib/response_set_spec.rb:4:in `<top (required)>''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `block in load_spec_files''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `map''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/configuration.rb:386:in `load_spec_files''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/command_line.rb:18:in `run''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:55:in `run_in_process''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:46:in `run''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/rspec-core-2.5.1/lib/rspec/core/runner.rb:10:in `block in autorun''
¡SIN EMBARGO! Hemos estado utilizando muchos otros archivos durante mucho tiempo que tienen una estructura idéntica. Por ejemplo, aquí hay otro que ha estado funcionando bien desde que fue creado:
/lib/smart_set.rb
module MyCompany
class SmartSet < Array
...
end
end
Y /spec/lib/smart_set_spec.rb
require ''spec_helper''
describe MyCompany::SmartSet do
describe "..." do
...
end
end
Este archivo tiene la estructura idéntica pero no causa ningún problema.
ResponseSet (la clase de problema) aparentemente tiene problemas de carga sin ninguna razón discernible. En la consola de los rieles, la primera vez que intento crear uno, aparece un error, pero luego puedo crear uno:
Loading development environment (Rails 3.0.4)
ruby-1.9.2-p136 :001 > rs = MyCompany::ResponseSet.new
LoadError: Expected /Users/my_stuff/projects/my_project/lib/response_set.rb to define ResponseSet
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:492:in `load_missing_constant''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:503:in `load_missing_constant''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:183:in `block in const_missing''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `each''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/activesupport-3.0.4/lib/active_support/dependencies.rb:181:in `const_missing''
from (irb):1
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/railties-3.0.4/lib/rails/commands/console.rb:44:in `start''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/railties-3.0.4/lib/rails/commands/console.rb:8:in `start''
from /Users/my_stuff/.rvm/gems/ruby-1.9.2-p136@my_project/gems/railties-3.0.4/lib/rails/commands.rb:23:in `<top (required)>''
from script/rails:6:in `require''
from script/rails:6:in `<main>''
ruby-1.9.2-p136 :002 > rs = MyCompany::ResponseSet.new
=> []
Además, añadiendo
require ''response_set''
en la parte superior de response_set_spec.rb permite que se ejecuten esas pruebas. Pero tal cosa no es necesaria para smart_set_spec.rb.
Lo siguiente está en su lugar en application.rb:
config.autoload_paths += %W(#{config.root}/lib)
config.autoload_paths += Dir["#{config.root}/lib/**/"]
config.autoload_paths += Dir["#{config.root}/app/models/**/"]
Ahora, entiendo que Rails tiene algún tipo de opinión sobre cómo la estructura de archivos debe coincidir con la estructura del espacio de nombres para este tipo de cosas, y hemos reestructurado nuestros módulos y archivos hacia este fin. Parece que se solucionó el problema (aunque estuvimos viendo algunos otros errores de carga extraños durante un tiempo cuando ejecutamos el conjunto completo de pruebas, estos desaparecieron misteriosamente). Sin embargo, todos aquí están desconcertados y no un poco molestos de que Rails sea tan inconsistente y nos gustaría saber por qué. Como puede ver, hay dos archivos que son idénticos en lo que respecta al espacio de nombres y la estructura de archivos, siendo tratados de manera completamente diferente. De hecho, tenemos cerca de una docena de otros archivos en el nivel superior de ''lib'' con espacios de nombre similares que nunca han causado ningún problema. ¿Alguien puede explicar qué diablos está pasando aquí?
Fue señalado en la dirección correcta por Brendan, verifique sus autoload_paths. Tuve un error similar y este fue el culpable para mí en application.rb:
config.autoload_paths += Dir["#{Rails.root}/app/models/[a-z]*"]
Mi aplicación no estuvo feliz una vez que comencé a usar módulos para los modelos junto con tener subdirectorios. Cambié el mío para cargar automáticamente solo los directorios que no son de módulo:
config.autoload_paths += Dir["#{Rails.root}/app/models/aaaaaaaaa"]
config.autoload_paths += Dir["#{Rails.root}/app/models/bbbbbbbbb"]
He sufrido el mismo problema con las clases de espacio de nombres que se autoloegen incorrectamente. Esta es la clave para resolverlo (de la respuesta de Brendan):
Debido a que nuestras autoload_paths incluían tanto lib como lib / **, Rails extrajo todos los archivos de todos los subdirectorios bajo lib. Desafortunadamente, parece ignorar el espacio de nombres implícito al cargar desde subdirectorios. Se esperaba que foo / base.rb definiera Base vs. Foo :: Base. Ese parece ser el defecto principal: load_missing_constant invoca search_for_file que devuelve cualquier archivo cuyo nombre coincida (p. Ej., En mi ejemplo, se devolvió foo / base.rb cuando coincidía con base.rb).
Y lo resolví moviendo todas mis clases de espacios de nombre, denominadas Events::Something
, a app/components/events/*
y creando un archivo app/components/events.rb
con el siguiente contenido:
%w(file1 file2 ...).each do |file|
require "events/#{file}"
end
Y aunque esto es un poco manual, funciona tanto para la aplicación como para la consola y para los modos de prueba.
Miré en la fuente de rieles y hay una
if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load
require_or_load file_path
raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless local_const_defined?(from_mod, const_name)
return from_mod.const_get(const_name)
elsif ...
Cláusula en el método load_missing_constant
. Puedo suponer que como se llama a require_or_load
antes de raise
, esta podría ser una razón por la que en la segunda llamada de tu ejemplo no hay error ...
Sería interesante ver un ejemplo mínimo en el que dos archivos con estructura idéntica se comportan de manera diferente. En su lugar, haría una copia de la aplicación y seguiría eliminando partes de ella mientras el comportamiento inconsistente esté presente para ver el ejemplo inconsistente mínimo.
PD: He enviado una pregunta similar aquí: http://www.ruby-forum.com/topic/2376956
Otro punto que vale la pena notar es si tiene la ruta correcta en la carpeta de servicios.
Por camino correcto, me refiero
engine_name / app / services / engine_name / your_service.rb
Accidentalmente olvidé la carpeta engine_name dentro de los servicios y obtuve este extraño comportamiento.
Tuvimos un problema similar que, después de excavar, resultó ser causado por los cambios en Rails 3.xy autoload_paths
.
Nuestro caso apareció solo en la prueba ( RAILS_ENV=test
). Cuando Rails estaba cargando los controladores, se apresuró a buscar el modelo coincidente de cada controlador (debido a un ActionController :: Base.wrap_parameters establecido en un inicializador). Finalmente, se redujo al método mencionado anteriormente (load_missing_constant). Debido a que nuestras autoload_paths incluían tanto lib como lib / **, Rails extrajo todos los archivos de todos los subdirectorios bajo lib. Desafortunadamente, parece ignorar el espacio de nombres implícito al cargar desde subdirectorios. Se esperaba que foo / base.rb definiera Base
vs. Foo::Base
. Ese parece ser el defecto principal: load_missing_constant
invoca search_for_file
que devuelve cualquier archivo cuyo nombre coincida (p. Ej., En mi ejemplo, se devolvió foo / base.rb cuando coincidía con base.rb).
Es difícil decir si esto es un error en Rails, ya que viola la asignación de espacio de nombres a directorio asumida por Ruby, o un uso incorrecto de autoload_paths.
Hemos solucionado este problema por ahora eliminando lib/**
de nuestras autoload_paths
y agregando las declaraciones de requisitos necesarias a application.rb.