2010-11-12 11 views
14

Ho le seguenti modelliaccepts_nested_attributes_for per collegare al record esistente, non crea uno nuovo

class Order < AR::Base 
    has_many :products 

    accepts_nested_attributes_for :products 
end 

class Product < AR::Base 
    belongs_to :order 
    has_and_belongs_to_many :stores 

    accepts_nested_attributes_for :stores 
end 

class Store < AR::Base 
    has_and_belongs_to_many :products 
end 

Ora ho una visione ordine dove voglio aggiornare i negozi per il prodotto. Il fatto è che voglio solo collegare i prodotti ai negozi esistenti nel mio db, non crearne di nuovi.

La mia forma nella visualizzazione ordine si presenta così (usando Formtastic):

= semantic_form_for @order do |f| 
    = f.inputs :for => :live_products do |live_products_form| 
    = live_products_form.inputs :for => :stores do |stores_form| 
     = stores_form.input :name, :as => :select, :collection => Store.all.map(&:name) 

Anche se la sua annidati funziona benissimo. Il problema è che quando seleziono un negozio e cerco di aggiornare l'ordine (e i prodotti e i negozi con esso), Rails prova a creare un nuovo negozio con quel nome. Voglio solo utilizzare il negozio esistente e collegare il prodotto a quello.

Qualsiasi aiuto apprezzato!

EDIT 1:

Alla fine ho risolto questo problema in modo molto rozzo:

# ProductsController 

def update 
    [...] 

    # Filter out stores 
    stores_attributes = params[:product].delete(:stores_attributes) 

    @product.attributes = params[:product] 

    if stores_attributes.present? 
    # Set stores 
    @product.stores = stores_attributes.map do |store_attributes| 
     # This will raise RecordNotFound exception if a store with that name doesn't exist 
     Store.find_by_name!(store_attributes[:name]) 
    end 
    end 

    @order.save 

    [...] 
end 

EDIT 2:

soluzione Pablo è molto più elegante e deve preferire il mio .

+0

Dopo aver esaminato la documentazione per a_n_a_f (http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html) ho ottenuto emozionato quando ho visto la possibilità update_only ma subito capito non c'è modo fare ciò che voglio fare (update_only aggiorna gli oggetti esistenti prima di crearne di nuovi). –

risposta

21

cercare di attuare un :reject_if che verificare se il negozio esiste già e quindi utilizzarlo:

class Product < AR::Base 
    belongs_to :order 
    has_and_belongs_to_many :stores 

    accepts_nested_attributes_for :stores, :reject_if => :check_store 

    protected 

    def check_store(store_attr) 
     if _store = Store.find(store_attr['id']) 
     self.store = _store 
     return true 
     end 
     return false 
    end 
end 

Ho questo codice che funziona benissimo in un progetto in corso.

Per favore, fatemi sapere se avete trovato una soluzione migliore.

+0

Molto intelligente! Ho risolto il problema in un modo molto meno elegante (modifico la mia domanda per mostrarlo) ma la tua soluzione dovrebbe funzionare meglio. –

+8

Questo non ha senso per me. 'self' in' check_store' è il prodotto ... e un prodotto non ha una relazione 'store' (è HABTM: memorizza). Quindi cosa fa in realtà questo codice? Inoltre, non sembra aggiornare il negozio trovato. – davemyron

+0

L'ho ottimizzato per funzionare a mio vantaggio trovando il record correlato esistente e aggiornando i suoi attributi * in reject_if *. Sembra hacky, ovviamente, ma ha funzionato. – davemyron

0

Ho avuto lo stesso problema e l'ho risolto aggiungendo: id all'elenco dei parametri nidificati.

def family_params 
    params.require(:family).permit(:user_id, :address, people_attributes: [:id, :relation, :first_name, :last_name) 
end 
+0

Ho scritto la mia domanda molto prima che uscisse Strong Parameters. –

Problemi correlati