2012-06-02 15 views
8

Tengo dos modelos con una asociación uno a muchos. Quiero establecer un valor predeterminado en el modelo hijo en la inicialización en función de algún estado del padre. Esto implica tener un fuego de devolución de llamada after_initialize en el niño que necesita acceder al padre a través de la asociación belongs_to. El problema es que cuando instanciamos al niño usando el método de compilación, la asociación con el padre es nula en la devolución de llamada after_initialize. ¿Es este comportamiento esperado? Estoy en los carriles 3.0.6Rails association nil in after_initialize

Un ejemplo de juguete:

class Merchant < ActiveRecord::Base 
    has_many :products 
end 

class Product < ActiveRecord::Base 
    belongs_to :merchant 

    after_initialize :set_default_value 

    def set_default_value 
     if merchant.state 
      self.foo = some_value 
     else 
      self.foo = some_other_value 
     end 
    end 
end 

Y en un controlador:

product = merchant.products.build 

En la llamada a set_default_value, comerciante es nulo aunque parece que shouldn 't ser.

+1

se ha guardado todavía la instancia comerciante original, antes de llamar comerciante. products.build? – Pasted

+0

Sí, el comerciante sería un registro existente en el archivo db, por lo que tendría un ID válido. – Dino

+1

Lo probé casi exactamente como lo tienes y funcionó para mí. La única diferencia es que 'productos de clase 'debe ser' producto de clase 'sin el' s'. –

Respuesta

1

me gustaría cambiar el código de la siguiente manera:

class Product < ActiveRecord::Base 
    ... 
    def set_default_value(state = merchant.state) 
    if state 
     self.foo = some_value 
    else 
     self.foo = some_other_value 
    end 
    end 
end 

luego cambia de persona que llama:

product = merchant.products.build(:state => merchant.state) 

Además, me he encontrado after_initialize devoluciones de llamada a ser lento. Entonces, otra opción es mover la lógica al constructor del producto.

product = merchant.products.build(:foo => merchant.state ? some_value : some_other_value) 

Esto también elimina la Ley de Demeter violación del código (es decir, el producto no debe saber/cuidado en qué estado del comerciante es).

0

estoy en los carriles 2,3 y puedo confirmar que

product = merchant.products.build 

no devolverá la asociación merchant_id correcta en una devolución de llamada after_initialize

pero me he dado cuenta de que funcionará correctamente con

product = merchant.products.new 

Creo que se corrigió con este compromiso (realmente no lo sé, no estoy muy familiarizado con el flujo de trabajo de Git):

https://github.com/rails/rails/issues/1842

Debido a que en los carriles 3.1.11 funciona tanto para build y new

0

Es probable que busque la inverse_of

has_many :products, inverse_of: :merchant