Lighthouse has a new layout. Prefer the old one? Return to the old layout, and switch back any time from the link at the top of each page.

This project is archived and is in readonly mode.

Rails3 RC2 - Autoloading does not work correctly when constaint is nested in class instead of module

#5476
17:07 <ruby-1.9.2-head> ~/test/railsrc2  > rails c
Loading development environment (Rails 3.0.0.rc2)

ruby-1.9.2-head > Relation
 => Relation(id: integer, created_at: datetime, updated_at: datetime) 


## Wrong !
ruby-1.9.2-head > Sequence::Relation
(irb):2: warning: toplevel constant Relation referenced by Sequence::Relation
 => Relation(id: integer, created_at: datetime, updated_at: datetime) 
##

ruby-1.9.2-head > Test::Relation
 => Test::Relation(id: integer, created_at: datetime, updated_at: datetime)

ruby-1.9.2-head > Sequence.class
 => Class 
ruby-1.9.2-head > Test.class
 => Module 

# Ok
ruby-1.9.2-head > require 'sequence/relation'
 => nil 
ruby-1.9.2-head > Sequence::Relation
 => Sequence::Relation(id: integer, group: integer, created_at: datetime, updated_at: datetime)


also if constant are accessed in different sequence it leads to different results:

17:10 <ruby-1.9.2-head> ~/test/railsrc2  > rails c
# OK
ruby-1.9.2-head > Sequence::Relation
 => Sequence::Relation(id: integer, group: integer, created_at: datetime, updated_at: datetime) 
ruby-1.9.2-head > Relation
 => Relation(id: integer, created_at: datetime, updated_at: datetime) 
ruby-1.9.2-head > Sequence::Relation
 => Sequence::Relation(id: integer, group: integer, created_at: datetime, updated_at: datetime)

As you can see using Relation before Sequence::Relation leads to an error that Sequence::Relation constant returns wrong object.

Reported by Robert Pankowecki · August 27th, 2010 @ 04:14 PM

State: wontfix
Milestone: none
Assigned to: nobody
Importance: Low

Activity

  1. Samuel Kadolph
    Samuel Kadolph

    This is easy to duplicate with plain classes.

      $ cat my_class.rb
      class MyClass
    
      end
      $ cat super_class.rb
      class SuperClass
    
      end
      $ cat super_class/my_class.rb
      class SuperClass
        class MyClass
    
        end
      end
      $ cat namespace.rb
      module Namespace
    
      end
      $ cat namespace/my_class.rb
      module Namespace
        class MyClass
    
        end
      end
      $ rails c
      Loading development environment (Rails 3.0.0.rc2)
      ruby-1.9.2-p0 > MyClass
       => MyClass
      ruby-1.9.2-p0 > Namespace::MyClass
       => Namespace::MyClass
      ruby-1.9.2-p0 > SuperClass::MyClass
      (irb):3: warning: toplevel constant MyClass referenced by SuperClass::MyClass
       => MyClass
    

    I ran into this problem and my solution was to avoid putting a class within another class. Fixing this problem would be awesome and I'll try to see if I can find part of dependencies is only 'on' for modules and not classes.

    August 27th, 2010 @ 09:05 PM

  2. Andrew White
    Andrew White
    • State changed from new to wontfix
    • Importance changed from to Low

    The problem here is that ruby searches ancestors for constants and Object is in the ancestor list of a Class but not of a Module. There's no way to intercept the call in ruby so we can't fix it.

    However, there's a couple of simple workarounds:

      # define the nested class in the sequence source file
      # sequence.rb
      class Sequence < ActiveRecord::Base
        class Relation < ActiveRecord::Base
        end
      end
    
      # require the nested class in the sequence source file
      # sequence.rb
      require_dependency 'sequence/relation'
      class Sequence < ActiveRecord::Base
      end
    
      # sequence/relation.rb
      class Sequence < ActiveRecord::Base
        class Relation < ActiveRecord::Base
        end
      end
    

    In the second workaround if you want the require_dependency at the top of the file you'll need to nest properly in the relation.rb file. If you want to define the Sequence::Relation class in one line then you'll need to put the require_dependency after the Sequence definition in sequence.rb

    August 27th, 2010 @ 11:28 PM

  3. Robert Pankowecki
    Robert Pankowecki

    Thank you for such a quick answer and the workarounds; I will definitely use the second one. Could you point me to some place which explains how require_dependency works or explain it by yourself in a few words ? I used to think I know how it works but after testing it few times i am not sure anymore.

    Is this:

    require_dependency 'sequence/relation'
    

    equal to this:

    Sequence::Relation
    

    in terms of autoloading and reload! behavior ? I mean: If i call it like that and than reload! than will Sequence::Relation constant be removed ?

    August 27th, 2010 @ 11:59 PM

  4. Robert Pankowecki
    Robert Pankowecki

    I think that:
    require - requires file once but reload! does not remove the constant
    load - loads the file every time is called which leads to redefining constant
    require_dependency - require file once and after reload! the constant is removed
    require_or_load - ??

    require_dependency did not work well for me on rails3.beta4 but I remember that there were some fixes about autoloading in rc1 and probably in rc2 so it should work fine now however I'm not sure if my intuition is right about what I stated here. Could you clarify it for me ? I could not find a single place that would explain using require_dependency and require_or_load well.

    August 28th, 2010 @ 12:05 AM

  5. Andrew White
    Andrew White

    Pretty much spot on - require_dependency basically makes the class you're requiring reloadable so any changes are picked up between requests.

    August 28th, 2010 @ 01:27 AM