I having a strange issue where certain models in a rails engine I am using are getting duplicated in the object space.
(rdb:1) ObjectSpace.each_object(::Class).each { |klass| puts klass.to_s + ": " + klass.object_id.to_s if klass.to_s.eql?("DynamicFieldsets::Field") }
DynamicFieldsets::Field: 66866100
DynamicFieldsets::Field: 71836380
2479
When this happens, I cannot use is_a? or equality checks to test that an object is an instance of the Field class. The problem only happens in development and it looks like it may be caused by cache_classes being off. I think the object from the previous request is still in the object space but I am not sure how to remove it.
This is easy to reproduce with remove_const
:
class X
def self.foo
"hello"
end
end
first_x = X.new
Object.send :remove_const, :X
class X
def self.foo
"world"
end
end
second_x = X.new
p first_x.class, first_x.class.object_id, second_x.class, second_x.class.object_id
# => X, <an_id>, X, <another_id>
p first_x.class.foo, second_x.class.foo
# => "hello", "world"
As you stated, you get this symptom only in development. When Rails reloads the classes, it simply calls remove_const
on the defined classes, to force them to be reloaded (using autoload
). Here's the code. Rails will actually call DynamicFieldsets::Field.before_remove_const
if it is defined, as explained here, how nice :-)
These should be garbage collected and you can trigger the GC with GC.start
, but if you have instances of the old classes lying around (like first_x
in my example), or subclasses, the old classes can not be garbage collected.
Note that is_a?
should work fine, in the sense that new instances will be kind_of?
and is_a?
of the new class. In my example:
first_x.is_a? X # => false
second_x.is_a? X # => true
This is the right behavior, as X
refers to the new class, not the old class.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With