mardi 29 septembre 2015

Namespaced model in Rails generating NameError: uninitialized constant

I have a folder structure like this:

app/
  models/
    bar/
      foo.rb
      connection.rb
    foo.rb

connection.rb is an "abstract class" for connecting to another database, so:

class Bar::Connection < ActiveRecord::Base
  self.abstract_class = true
  establish_connection "outsidedb_#{Rails.env}"
end

bar/foo.rb is for accessing the foos table from outsidedb, so:

class Bar::Foo < Bar::Connection
end

And foo.rb is for accessing the foos table from the app's db, so:

class Foo < ActiveRecord::Base
end

From the rails console if I do Foo.first or Bar::Foo.first things behave as a I would expect in that I get the first entry from the foos table of the app db and the external db, respectively.

However, if I try to access Foo from within bar/foo.rb I get the following:

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

I can obviously get things working, but I'm looking for a sounder understanding of what's going on. I'm assuming I'm missing something between Ruby's constant/class evaluation and Rail's builtin auto-loading...

  1. What is .parent returning (not the 'parent' class)?
  2. Why do I get the error in .test, but I don't get it in the rails console?
  3. Why does Object::Foo seem to work? Is it the right thing to do?
  4. Why does ActiveRecord::Base::Foo work, but with a warning?
  5. There a more rails way to do what I've done without just renaming one of my foo.rb classes?

I'm on Rails '3.2.13' and Ruby 1.9.3-p194, just so you know!

Aucun commentaire:

Enregistrer un commentaire