ruby on rails - root_path - Modelo espaciado por nombre en Rails que genera NameError: constante no inicializada
routes ror (2)
Tengo una estructura de carpetas como esta:
app/
models/
bar/
foo.rb
connection.rb
foo.rb
connection.rb
es una "clase abstracta" para conectarse a otra base de datos, entonces:
class Bar::Connection < ActiveRecord::Base
self.abstract_class = true
establish_connection "outsidedb_#{Rails.env}"
end
bar/foo.rb
es para acceder a la tabla de foos
desde outsidedb
, entonces:
class Bar::Foo < Bar::Connection
end
Y foo.rb
es para acceder a la tabla de los foos
desde la base de datos de la aplicación, así que:
class Foo < ActiveRecord::Base
end
Desde la consola de rieles, si hago Foo.first
o Bar::Foo.first
las Bar::Foo.first
cosas se comportan como esperaría, obtengo la primera entrada de la tabla de los foos
de la aplicación db y la db externa, respectivamente.
Sin embargo, si intento acceder a Foo
desde bar/foo.rb
obtengo lo siguiente:
class Bar::Foo < Bar::Connection
def self.test
Bar::Foo.first #=> works
Foo.first #=> NameError: uninitialized constant Bar::Foo::Foo
end
def self.other_test
Foo.parent #=> Object
Foo.superclass #=> ActiveRecord::Base
Object::Foo.first #=> works
ActiveRecord::Base::Foo.first #=> works, but with "warning: toplevel constant
# Foo referenced by ActiveRecord::Base::Foo
end
end
Obviamente puedo hacer que las cosas funcionen, pero estoy buscando una mejor comprensión de lo que está pasando. Asumo que me falta algo entre la constante / evaluación de clase de Ruby y la carga automática integrada de Rail ...
- ¿Qué es el regreso de
.parent
(no la clase ''padre'')? - ¿Por qué obtengo el error en
.test
, pero no lo obtengo en la consola de rails? - ¿Por qué
Object::Foo
parece funcionar? ¿Es lo correcto? - ¿Por qué funciona
ActiveRecord::Base::Foo
, pero con una advertencia? - Hay una manera más de hacer todo lo que he hecho sin cambiar el nombre de una de mis clases
foo.rb
?
¡Estoy en Rails ''3.2.13''
y Ruby 1.9.3-p194
, solo para que lo sepan!
Aquí hay documentación sobre el método .parent
que debería ayudar a responder su primera pregunta: http://guides.rubyonrails.org/active_support_core_extensions.html#extensions-to-module-parents . Desplácese hasta la Sección 3.3 para la parte relevante.
El método .parent
viene con soporte activo que proporciona extensiones de Ruby a los componentes de Ruby on Rails. El método .parent
es una extensión para Módulos y devuelve el nombre del módulo que contiene la clase actual. Entonces, si lo hizo Bar::Foo.parent
, el valor de retorno debería ser Bar
.
Sin embargo, cuando la clase no tiene un módulo adjunto, el valor de retorno se configurará por defecto en Object
. Esto es lo que sucede cuando haces Foo.parent
ya que Foo
aquí se refiere a la clase Foo
que no está en el espacio de nombres de Bar
.
La magia relevante de Rails: https://github.com/rails/rails/blob/c9bbac46ddfc68caff6cd8a95c8d0fd045bd9201/activesupport/lib/active_support/core_ext/module/introspection.rb
Tu problema puede ser arreglado con
::Foo.first
Aquí ::Foo
indica la clase Foo
en el espacio de nombres superior.
Tu problema proviene del hecho de que hay otra clase de Foo
en el espacio de nombres ( Bar
) en el que estás trabajando. Por lo tanto, debes ser explícito.
En cuanto a la pregunta por qué Object::Foo
funciona (con advertencias), es un comportamiento (menos) conocido de búsqueda de nombre en Ruby. Por favor, mira este artículo para más detalles.