2015-12-27 14 views
8

Talvolta la classe padre non carica tutti i relativi figli in una richiamata after_save da parte del figlio.Associazione di rail non caricata correttamente

Ho due modelli:

class Parent < ActiveRecord::Base 
    has_many :children 

    def update_something 
    # explained below 
    end 
end 

class Child < ActiveRecord::Base 
    belongs_to :parent 

    after_save :tell_parent_to_update 

    def tell_parent_to_update 
    parent.update_something 
    end 
end 

ho un test di Io corro su di esso, che ha appena controlla 2 cose. parent.children.count e parent.children.length. Entrambi dovrebbero essere 4. Mi rendo conto che il conteggio a volte è diverso, ma (per quanto ne so) non dovrebbe essere qui.

Se io definisco update_something di iterare poco più children:

def update_something 
    children.each do |child| 
    end 
end 

il test fallisce - il ciclo verrà eseguito una volta (e tornerà la matrice di un singolo bambino - la prima child creato) .

Altrimenti, posso inserire qualsiasi codice purché non menzioni children e funzionerà. È come se la chiamata ai bambini stia causando l'associazione a caricare la cosa sbagliata.

Forzare una ricarica ripara:

def update_something 
    children(true).each do |child| 
    end 
end 

ma questo è hacky e avrei preferito risolvere il problema principale, se possibile.

È questo il mio bug, o un baco (e se è così c'è qualcosa che posso fare per aggirare questo)?

Dubito che importi ma questo è un ambiente di test che utilizza sqlite3. Anche se fallirà in un ambiente di sviluppo se creo e collaudo i record in una singola sessione di console di sviluppo.

+0

'children.each do | child |' or 'Children.each do | child |'? –

+0

forse qualcosa a che fare con le parole chiave, solo a indovinare. – Nithin

+0

L'ho pensato anch'io all'inizio, ma nel codice reale ora è molto isolato e i nomi effettivi dei modelli/metodi sono estremamente specifici del dominio e sfortunatamente non sono parole chiave. –

risposta

3

salto nel buio, ma potrebbe essere necessario inverse_of, che credo memorizza gli oggetti associati nello stesso blocco di memoria, in contrasto con i diversi blocchi di un approccio standard creerebbe:

#app/models/parent.rb 
class Parent < ActiveRecord::Base 
    has_many :children, inverse_of: :parent 
    ... 
end 

#app/models/child.rb 
class Child < ActiveRecord::Base 
    belongs_to :parent, inverse_of: :children 
    ... 
end 

Nella mia esperienza, ho trovato inverse_of consente di chiamare i dati associativi negli altri modelli. Ad esempio, chiamando parent.update_somethingsenzainverse_of si potrebbe generare un errore (se parent non è stato definito in modo esplicito) oppure è necessario creare nuovamente l'oggetto parent.

C'è un good write-up here.

-

sarò cancellare la risposta, se non aiuta.

+0

Purtroppo non sembra averlo risolto. Secondo l'articolo e quello che ho trovato online, a partire dalle guide 4.1 (sono 4.2) lo gestisco automaticamente. Sarebbe utile lasciare questa risposta anche se, nel caso in cui lo risolva per qualcuno in futuro. –

+0

Va bene, grazie per l'heads-up. Lascerò perdere i posteri! –

0

Ciò è probabilmente dovuto al fatto che i figli del genitore sono caricati con entusiasmo a un certo punto nel codice prima che tell_parent_to_update venga eseguito.

parent.children.count eseguirà una query SQL e restituirà il numero di figli presenti nel DB, mentre parent.children.length restituirà la lunghezza dell'array figlio (che è probabilmente già caricato con carico).

Vorrei suggerire di provare manualmente a salvare 1 oggetto figlio dalla console di rails e vedere se la lunghezza e il numero di figli in update_something è uguale. Se lo è, probabilmente il test sta fallendo a causa di un codice precedente.

Problemi correlati