From: Teleolurian Date: 2008-06-19T01:29:02+09:00 Subject: Re: Object not missing constant... what am I doing wrong? On Jun 17, 9:50 pm, Bryan JJ Buckley wrote: > Hi, > > Looks like you're trying to reinvent something that Rails already > tries to do for you, and the two mechanisms aren't playing nicely > together. > > 2008/6/18 Teleolurian : > > > > > Background: I'm using ActiveRecord to handle some bulk uploads. I > > decided it would be a good idea to put all my models into subfolders, > > then load them with autoload [essentially, so I can namespace > > everything into a module]. Here's the relevant code (i'm using > > MODULENAMEBase.rb as the naming convention for the class that does > > establish_connection): > > > module DBNamespace > >  def self.included(m) > >    @models_path = "models/#{m}" > >    require "#{@models_path}/#{m}Base.rb" > >    Dir.new(@models_path).entries.grep(/\.rb$/).collect do |fn| > >      cname = fn.sub(/\.rb$/, '') > >      cname[0] = cname[0].chr.upcase > >      m.autoload(cname, "#{@models_path}/#{fn}") unless fn == > > "#{m}Base.rb" > >    end > >  end > > > end > > > module PL > >  include DBNamespace > > end > > > ---- > > Right now, I can check PL.autoload?(:Agent) and get the correct path; > > I can even load the constant with PL.const_get(:Agent). However, > > trying PL::Agent gives me a: > > > /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/ > > dependencies.rb:278:in `load_missing_constant': uninitialized constant > > PL::Agent (NameError) > >        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/ > > active_support/dependencies.rb:467:in `const_missing' > > This happens because when you try to access PL::Agent directly, your > PL module hasn't been explicitely included into anything, and > therefore your `included` block was never called. Hence, no constant > PL::Agent. > > > > > And doing an include PL; Agent gives me the odder: > > > /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/active_support/ > > dependencies.rb:252:in `load_missing_constant': Object is not missing > > constant Agent! (ArgumentError) > >        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/ > > active_support/dependencies.rb:467:in `const_missing' > >        from /usr/lib/ruby/gems/1.8/gems/activesupport-2.1.0/lib/ > > active_support/dependencies.rb:479:in `const_missing' > >        from header.rb:7 > > This is where you're tripping over Rails's ActiveSupport autoloading. > First you include PL, which includes DBNamespace, and calls > DBNamespace::included, and that terminates properly. At this point, > you have added Agent as autoloadable... That would (probably) be fine > in a pure Ruby application. But Rails already has an autoloading > mechanism, which is based on overriding Class#const_missing, and which > is apparently called as soon as you reference the (as yet unknown) > constant Agent. This apparantly is already known (probably due to your > manual addition of it to the autoload map). > > > > > Can anybody clear this up? > > I would recommend that if you want to namespace models like this, let > Rails to the work its own way for you. Put files in a hierarchical > structure under app/models or lib/ (which are both in the load path > anyway), and name those files consistently. For example, in > db_namespace.rb, just have > >   Dir["#{File.basename(__FILE__, 'rb')}/**/*.rb"].each do |requirement| >     require requirement >   end > >  and in db_namespace/agent.rb, do something like > >   module DBNamespace >     class Agent >       # stuff >     end >   end > > Then Agent is autoloaded the first time ruby sees DBNamespace::Agent. > > Apologies if I've missed some of the point of what you were trying to > do, but I do recommend that you stick to Rails conventions when doing > something like this, as trying to second-guess all the ActiveSupport > core extensions to Module and Class are almost guaranteed to cause > headaches. > > -- > JJ Thank you very much! Adding module namespaces around the model classes was what I needed to do. Probably should have been obvious, but I've just come back to ruby after a bit of a hiatus :)