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
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 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 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 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 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 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>