2012-06-02 19 views
8

Ich habe zwei Modelle mit einer eins zu viele Assoziation. Ich möchte einen Standardwert für das untergeordnete Modell bei der Initialisierung basierend auf einem bestimmten Status des übergeordneten Elements festlegen. Dies beinhaltet ein Callback nach dem Initialisieren von Callbacks auf das Kind, das über die assignes_to-Assoziation auf das Elternobjekt zugreifen muss. Das Problem besteht darin, dass bei der Instanziierung des untergeordneten Elements mit der build -Methode die Zuordnung zum übergeordneten Element im after_initialize-Callback gleich Null ist. Ist das erwartetes Verhalten? Ich bin auf Schienen 3.0.6Rails association nil in after_initialize

Ein Spielzeug Beispiel:

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 

Und in einem Controller:

product = merchant.products.build 

In dem Aufruf von set_default_value, Händler ist gleich Null, obwohl es scheint, dass es shouldn nicht sein.

+1

Hat der ursprüngliche Kaufmann Instanz noch gespeichert, bevor Sie Händler nennen. products.build? – Pasted

+0

Ja, der Händler wäre ein existierender Datensatz in der Datenbank, also hätte er eine gültige ID. – Dino

+1

Ich habe es fast genau versucht, wie du es hast und es hat für mich funktioniert. Der einzige Unterschied ist, dass "Klassenprodukte" ohne "s" "Produktklasse" sein sollten. –

Antwort

1

Ich würde den Code wie folgt ändern:

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 

Dann Anrufer ändern:

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

Außerdem habe ich after_initialize Rückrufe zu langsam gefunden. Eine weitere Option besteht darin, die Logik in den Builder für das Produkt zu verschieben.

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

Dies auch das Gesetz des Demeter beseitigt Verletzung aus dem Code (das heißt das Produkt soll nicht wissen/egal, was der Händler Zustand ist).

0

Ich bin auf Schienen 2.3 und ich kann bestätigen, dass

product = merchant.products.build 

die korrekte merchant_id Vereinigung in einem after_initialize Rückruf nicht zurück

aber ich habe festgestellt, dass es mit

korrekt funktioniert
product = merchant.products.new 

Ich denke, es wurde mit diesem Commit behoben (ich weiß es nicht wirklich, ich kenne den Git-Workflow nicht wirklich):

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

Da in Schienen 3.1.11 es funktioniert sowohl für build und new

0

Sie wahrscheinlich Blick für inverse_of

has_many :products, inverse_of: :merchant