Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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!

like image 660
Gray Kemmey Avatar asked Nov 18 '25 16:11

Gray Kemmey


1 Answers

Your problem can be fixed with

::Foo.first

Here ::Foo indicating the class Foo in top namespace.

You problem comes from the fact, that there is another Foo class in the namespace (Bar) you are working in. So you should be explicit.

As to the question why Object::Foo works (with warnings), it's a (less) known behaviour of name lookup in Ruby. Please see this article for more details.

like image 63
dimakura Avatar answered Nov 21 '25 08:11

dimakura



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!