2012-03-15 10 views
9

in un progetto Ruby on Rails Sto tentando di accedere agli oggetti di associazione su un ActiveRecord prima di salvare tutto nel database.Ruby on Rails has_many tramite gli oggetti di associazione prima di salvare

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 

Se io costruisco il mio oggetto in questo modo: purchase = Purchase.new(item_ids: [1, 2, 3]) e cercare di salvare il metodo item_validation non ha la collezione di oggetti ancora popolato, quindi, anche se gli elementi sono stati impostati impostarlo non ottiene un possibilità di chiamare il metodo check_something su uno di essi.

È possibile accedere alla raccolta di articoli prima che il modello di acquisto e i modelli di associazione siano mantenuti in modo che possa eseguire convalide contro di essi?

Se cambio il mio metodo item_validation di essere:

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 

sembra funzionare il modo in cui voglio che, però trovo difficile credere che non c'è modo di accedere direttamente alla raccolta oggetti con rotaie prima del mio acquisto e dei record associati salvati nel database.

risposta

0

Avete documentazione che indica che purchase = Purchase.new(item_ids: [1, 2, 3]) fa ciò che vi aspettate?

Per me sembra che si stia semplicemente impostando l'attributo non di database 'item_ids' su un array (ovvero non creando un'associazione).

Il modello di acquisto non deve nemmeno avere colonne di chiavi esterne da impostare direttamente. Invece ci sono voci nella tabella purchase_items che hanno un purchase_id e item_id. Per creare un collegamento tra il tuo acquisto e i tre articoli devi creare tre voci nella tabella dei join.

Che cosa succede se si esegue questa operazione, invece ?:

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

Prova ad aggiungere l'argomento inverse_of: nel has_many e belongs_to definizioni. L'argomento inverse_of è il nome della relazione sul l'altro modello, per esempio:

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

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

Non dimenticare di aggiungere anche sulle altre classi, come PurchaseItem e voce

Speranza che aiuta

1

Rimuovere il proprio metodo item_ids= - i binari ne generano uno (vedere collection_singular_ids=ids). Questo potrebbe già risolvere il tuo problema.

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 

La seconda cosa che mi viene in mente guardando il tuo codice: Spostare la validazione alla classe Item. Quindi:

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 

Il tuo record Purchase sarà anche valida se una delle Item s non è valido.

0

Suppongo che non è possibile accedervi poiché id di Purchase non è disponibile prima della registrazione salvata. Ma come si parla si ha accesso a livello di prima associazione purchase_items, in modo da poter estrarre tutti gli ID e passarli in where per Item:

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