Domanda

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.

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top