2012-03-15 8 views
9

w projekcie Ruby on Rails Próbuję uzyskać dostęp do obiektów skojarzenia w ActiveRecord przed zapisaniem wszystkiego w bazie danych.Ruby on Rails has_many through obiektów asocjacyjnych przed zapisaniem

class Purchase < ActiveRecord::Base 

    has_many :purchase_items, dependent: :destroy 
    has_many :items, through: :purchase_items 

    validate :item_validation 

    def item_ids=(ids) 
    ids.each do |item_id| 
     purchase_items.build(item_id: item_id) 
    end 
    end 

    private 

    def item_validation 
    items.each do |item| 
     ## Lookup something with the item 
     if item.check_something 
     errors.add :base, "Error message" 
     end 
    end 
    end 

end 

Jeśli buduję mój obiekt tak: purchase = Purchase.new(item_ids: [1, 2, 3]) i spróbuj go zapisać metodę item_validation nie posiada jeszcze zbieranie przedmiotów zaludnione, więc mimo, że pozycje zostały ustawione zestaw nie dostać szansę na wywołanie metody check_something na dowolnym z nich.

Czy można uzyskać dostęp do kolekcji przedmiotów, zanim mój model zakupu i modele asocjacji zostaną utrwalone, aby można było przeprowadzić walidację z nimi?

Jeśli mogę zmienić metodę item_validation być:

def item_validation 
    purchase_items.each do |purchase_item| 
    item = purchase_item.item 
    ## Lookup something with the item 
    if item.something 
     errors.add :base, "Error message" 
    end 
    end 
end 

wydaje się działać tak, jak ma to jednak trudno mi uwierzyć, że nie ma sposobu, aby uzyskać bezpośredni dostęp do kolekcji elementów z szyny przed moim zakupem i powiązane zapisy są zapisywane w bazie danych.

Odpowiedz

0

Czy masz dokumentację, która wskazuje, że purchase = Purchase.new(item_ids: [1, 2, 3]) spełnia Twoje oczekiwania?

Dla mnie, który wygląda tak, jak ty właśnie ustawiasz atrybut nie-bazy danych "id_produktów" na tablicę (tj. Nie tworząc powiązania).

Twój model zakupu nie powinien zawierać żadnych kolumn klucza obcego do ustawienia bezpośrednio. Zamiast tego są pozycje w tabeli purchase_items, które mają purchase_id i item_id. Aby utworzyć łącze między zakupem a trzema przedmiotami, musisz utworzyć trzy wpisy w tabeli stolików.

Co się stanie, jeśli po prostu zrobić to zamiast ?:

purchase = Purchase.new 
purchase.items = Item.find([1,2,3]) 
1

Spróbuj dodając argument inverse_of: w has_many i belongs_to definicji. Inverse_of argumentem jest to nazwa relacji na inny model, na przykład:

class Post < ActiveRecord::Base 
    has_many :comments, inverse_of: :post 
end 

class Comment < ActiveRecord::Base 
    belongs_to :post, inverse_of: :comments 
end 

Nie zapomnij go dodać również w innych klasach, takich jak PurchaseItem i rzecz

nadzieję, że pomoże

1

Usuń własną metodę item_ids= - szyny generują jeden dla ciebie (patrz collection_singular_ids=ids). To może już rozwiązać Twój problem.

class Purchase < ActiveRecord::Base 

    has_many :purchase_items, dependent: :destroy 
    has_many :items, through: :purchase_items 

    validate :item_validation 

    private 

    def item_validation 
    items.each do |item| 
     ## Lookup something with the item 
     if item.check_something 
     errors.add :base, "Error message" 
     end 
    end 
    end 

end 

Drugą rzeczą, która przychodzi mi do głowy patrząc na kodzie: Przenieś walidacji do klasy Item. Więc:

class Purchase < ActiveRecord::Base 
    has_many :purchase_items, dependent: :destroy 
    has_many :items, through: :purchase_items 
end 

class Item < ActiveRecord::Base 
    has_many :purchase_items 
    has_many :purchases, through: :purchase_items 

    validate :item_validation 

    private 

    def item_validation 
     if check_something 
     errors.add :base, "Error message" 
     end 
    end 
end 

Twój Purchase rekord będzie również nieważny, jeżeli jeden z Item s jest nieprawidłowy.

0

Zakładam, że nie masz do nich dostępu, ponieważ id z Purchase nie jest dostępna przed zapisaniem zapisu. Ale jak wspomniałeś masz dostęp do stowarzyszenia pierwszego stopnia purchase_items, więc można wyodrębnić wszystkie identyfikatory i przekazać je w where dla Item:

items = Item.where(purchase_item_id: purchase_items.map(&:id))