This project is archived and is in readonly mode.

#5476 ✓wontfix
Robert Pankowecki

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

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

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.

Comments and changes to this ticket

  • Samuel Kadolph

    Samuel Kadolph August 27th, 2010 @ 09:05 PM

    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.

  • Andrew White

    Andrew White August 27th, 2010 @ 11:28 PM

    • 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

  • Robert Pankowecki

    Robert Pankowecki August 27th, 2010 @ 11:59 PM

    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 ?

  • Robert Pankowecki

    Robert Pankowecki August 28th, 2010 @ 12:05 AM

    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.

  • Andrew White

    Andrew White August 28th, 2010 @ 01:27 AM

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

Create your profile

Help contribute to this project by taking a few moments to create your personal profile. Create your profile »

<h2 style="font-size: 14px">Tickets have moved to Github</h2>

The new ticket tracker is available at <a href="https://github.com/rails/rails/issues">https://github.com/rails/rails/issues</a>

Pages