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::Fooparece 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.