2012-03-06 15 views
7

Avendo uno strano problema in cui alcuni modelli di un motore di rotaie che sto utilizzando vengono duplicati nello spazio oggetti.Duplicazione della classe nello spazio oggetti object_id

(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 

Quando ciò accade, non posso usare is_a? o controlli di uguaglianza per verificare che un oggetto sia un'istanza della classe Field. Il problema si verifica solo durante lo sviluppo e sembra che potrebbe essere causato da cache_classes disattivato. Penso che l'oggetto della richiesta precedente si trovi ancora nello spazio dell'oggetto, ma non sono sicuro di come rimuoverlo.

+1

+1, questo sembra impossibile. Come possono esserci due oggetti legati alla stessa costante? Cosa fa "puts" # {klass.inspect}: # {klass.object_id} "if ..." output? –

+0

Quale classe di ordinamento è 'DynamicFieldsets :: Field'? Da dove proviene? –

+0

DynamicFieldsets :: Field è un oggetto ActiveRecord :: Base proveniente da un motore di rotaie. Quando si ispezionano le classi nello spazio oggetti, sono esattamente le stesse eccetto per l'ID oggetto. Qualsiasi metodo per verificare se sono uguali restituirà true tranne per quelli che controllano l'oggetto, ad esempio is_a? . – jeremiahishere

risposta

2

Questo è facile da riprodurre con 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" 

Come lei ha affermato, si ottiene questo sintomo solo nello sviluppo. Quando Rails ricarica le classi, chiama semplicemente remove_const sulle classi definite, per forzarle a ricaricarle (usando autoload). Here's the code. Rails effettivamente chiamare DynamicFieldsets::Field.before_remove_const se è definito, come spiegato here, che bello :-)

Questi dovrebbero essere garbage collection e si può innescare il GC con GC.start, ma se avete istanze delle vecchie classi in giro (come first_x nel mio esempio), o sottoclassi, le vecchie classi non possono essere raccolte con garbage collection.

Si noti che is_a? dovrebbe funzionare correttamente, nel senso che le nuove istanze saranno kind_of? e is_a? della nuova classe. Nel mio esempio:

first_x.is_a? X # => false 
second_x.is_a? X # => true 

questo è il comportamento giusto, come X si riferisce alla nuova classe, non la vecchia classe.

Problemi correlati