2010-04-09 10 views
20

Ich habe ein paar Modelle wie soRuby on Rails - verschachtelte Attribute: Wie kann ich das übergeordnete Modell Modell von Kind Zugang

class Bill < ActiveRecord::Base 
    has_many :bill_items 
    belongs_to :store 

    accepts_nested_attributes_for :bill_items 
end 

class BillItem <ActiveRecord::Base 
    belongs_to :product 
    belongs_to :bill 

    validate :has_enough_stock 

    def has_enough_stock 
    stock_available = Inventory.product_is(self.product).store_is(self.bill.store).one.quantity 
    errors.add(:quantity, "only #{stock_available} is available") if stock_available < self.quantity 
    end 
end 

Die obige Validierung so offensichtlich nicht, weil nicht funktioniert, wenn ich lese die bill_items von verschachtelten Attributen innerhalb des Rechnungsformulars, die Attribute bill_item.bill_id oder bill_item.bill sind vor dem Speichern nicht verfügbar.

Also, wie mache ich so etwas?

+0

Ich löste dies, indem ich einen Aufruf zurück zu der Assoziation hinzufügte,: before_add =>: set_nest – TMaYaD

Antwort

18

So habe ich es schließlich gelöst; indem Eltern auf Rückruf

has_many :bill_items, :before_add => :set_nest 

private 
    def set_nest(bill_item) 
    bill_item.bill ||= self 
    end 
+1

Ja! Es nervt mich in letzter Zeit. Ich wünschte, es wäre automatisch, man könnte eine allgemeinere Version schreiben, wenn Callback-Funktionen gegen den Assoziations-Proxy (wie Assoziationserweiterungen) anstelle des Assoziationseigners ausgeführt würden. – ilpoldo

0

Ja, diese Art von Problem kann nervig sein. Sie könnten versuchen, ein virtuelles Attribut zu Ihrem Bill Artikel Modell wie folgt ergänzt:

class BillItem <ActiveRecord::Base 
    belongs_to :product 
    belongs_to :bill 

    attr_accessible :store_id 

    validate :has_enough_stock 

    def has_enough_stock 
    stock_available = Inventory.product_is(self.product).store_is(load_bill_store).one.quantity 
    errors.add(:quantity, "only #{stock_available} is available") if stock_available < self.quantity 
    end 

    private 

    def load_bill_store 
    Store.find_by_id(self.store_id) 
    end 
end 

Und dann in der Ansicht Sie ein verstecktes Feld wie folgt hinzufügen könnte:

<%= bill_item.hidden_field :store_id, :value => store_id %> 

Dies war nicht Test aber es könnte funktionieren. Möglicherweise ist es nicht wünschenswert, die store_id im html zu haben, aber das ist vielleicht kein Problem. Lassen Sie mich wissen, ob das hilft.

1

Die bill_item.bill sollte verfügbar sein, könnten Sie versuchen, eine Erhöhung zu tun. Bill.inspect, um zu sehen, ob es da ist oder nicht, aber ich denke, das Problem ist woanders.

+0

Auch wenn es nicht verfügbar ist, könnte das OP einfach einen before_validation Callback hinzufügen, um es zu setzen. Die BillItems sollten ihre eigenen IDs oder die zu validierende ID der übergeordneten Bill nicht kennen müssen. – hornairs

1

I "fixed" es durch Eltern in einer Callback-Einstellung:

class Bill < ActiveRecord::Base 
    has_many :bill_items, :dependent => :destroy, :before_add => :set_nest 
    belongs_to :store 

    accepts_nested_attributes_for :bill_items 

    def set_nest(item) 
    item.bill ||= self 
    end 
end 

class BillItem <ActiveRecord::Base 
    belongs_to :product 
    belongs_to :bill 

    validate :has_enough_stock 

    def has_enough_stock 
     stock_available = Inventory.product_is(self.product).store_is(self.bill.store).one.quantity 
    errors.add(:quantity, "only #{stock_available} is available") if stock_available < self.quantity 
    end 
end 

Die set_nest Methode der Trick. Ich wünschte, es wäre Standard mit acesses_nested_attributes_for.

7

In Rails 4 (prüften auf keine früheren Versionen) Sie das übergeordnete Modell, indem Sie die inverse_of Option auf has_many oder has_one zugreifen:

class Bill < ActiveRecord::Base 
    has_many :bill_items, inverse_of: :bill 
    belongs_to :store 

    accepts_nested_attributes_for :bill_items 
end 

Dokumentation: Bi-directional associations

+0

Dies ist die richtige Antwort für Schienen 4 – Abs

Verwandte Themen