2014-10-28 5 views
5

Esiste un modo per evitare il salvataggio automatico dell'oggetto mentre si assegnano gli attributi di raccolta (metodo_collection_singular_ids = ids)?Rails 3 non può eseguire la convalida per oggetto persistente quando usa collection_singular_ids = metodo ids

ad esempio, ho il seguente modello di Test e Package, Package ha molti test. L'utente può creare un pacchetto con un numero di test.

Nessun problema sulla convalida quando oggetto pacchetto è nuova.

1.9.2 :001> package = Package.new(:name => "sample", :cost => 3.3, :test_ids => [1,2,3,4]) 
=> #<Package id: nil, name: "sample", cost: 3.3> 
1.9.2 :002> package.test_ids 
=> [1, 2, 3, 4] 
1.9.2 :003> package.save 
=> false 
1.9.2 :004> package.save! 
ActiveRecord::RecordInvalid: Validation failed: This package should have at most three tests 
1.9.2: 005> package.test_ids = [1,2] 
=> [1, 2] 
1.9.2 :005> package.save! 
=> true 

Ma non potevo colpire at_most_3_tests metodo con persistito oggetto del pacchetto.

Registrati record della tabella è creata direttamente durante l'assegnazione di ID test

1.9.2: 006> package 
=> #<Package id: 1, name: "sample", cost: 3.3> 
1.9.2: 007> package.test_ids 
=> [1,2] 
1.9.2: 007> package.test_ids = [1,2,3,4,5] 
=> [1,2,3,4,5] 
1.9.2: 008> package.test_ids 
=> [1,2,3,4,5] 

requisito del cliente è l'interfaccia a discesa per la selezione di più test in forma pacchetto e utilizzato anche select2 plugin per jQuery per discesa. Codice Rhmtl assomiglia

<%= form_for @package do |f| %> 
    <%= f.text_field :name %> 
    <div> <label>Select Tests</label> </div> 
    <div> 
    <%= f.select "test_ids", options_for_select(@tests, f.object.test_ids), {}, { "data-validate" => true, :multiple => true} %> 
    </div> 

Please help me per risolvere questo problema.

risposta

5

Per il numero limite di associazioni

È possibile utilizzare i seguenti convalide come la seguente, invece del metodo:

has_many :tests, :length => { :maximum => 3 } 

Per l'utilizzo di più selezionare

ho questo problema prima, e l'ho risolto usando il seguente codice:

<%= f.select(:test_ids, options_from_collection_for_select(@tests, :id, :name, @promotion.test_ids), {}, {multiple: true, "data-validate" => true}) => 

Penso che options_from_collection_for_select, leggere le categorie di post esempio da questo link può aiutare.

per la convalida

ho usato validates_associated, come il seguente:

validates_associated :tests 

Per ottenere i vecchi attributi per oggetto persistente

È possibile utilizzare reload per il record attivo come il successivi:

1.9.2: 006> package 
=> #<Package id: 1, name: "sample", cost: 3.3> 
1.9.2: 007> package.test_ids 
=> [1,2] 
1.9.2: 007> package.test_ids = [1,2,3,4,5] 
=> [1,2,3,4,5] 
1.9.2: 007> package.reload 
=> #<Package id: 1, name: "sample", cost: 3.3> 
1.9.2: 008> package.test_ids 
=> [1,2] 

Oppure si può controllare la convalida di oggetto di pacchetto, se è falsa ricaricarlo:

unless package.valid? 
    package.reload 
end 
+0

Non riesco a chiamare package.valid? perché ogni volta che si assegna un array di ID, viene automaticamente attivata l'azione di salvataggio. Ad esempio package.test_ids = [1,2,3,4,5] –

+0

@ManivannanJeganathan Ho aggiornato la mia risposta per utilizzare questa convalida 'has_many: tests,: length => {: maximum => 3}' –

+0

La mia convalida non è solo in base alla lunghezza. Ho appena dato un codice di esempio. I parametri [: pacchetto] dovrebbero sempre avere parametri test_ids come {: cost => 3.4,: test_ids => [1,2,3,4,5]}. Semplicemente ho bisogno di colpire il metodo di convalida nel modello di pacchetto e nel modulo di rendering se fallisce la convalida. Posso colpire il metodo di validazione con l'aiuto della tua risposta chiamando '' 'validates_associated: package''' nel modello PackageTest. Ma se la convalida fallisce in relazione alla validazione di test_ids, eccezione sollevata invece di restituire vero o falso. Codice esadecimale '' 'if @ package.update_attributes params [: package] else render" form "' '' –

3

Se stai assegnare manualmente i test_ids nel controller, suggerirei di aggiornare l'intero oggetto con gli attributi nidificati anziché.Ciò presuppone che params[:package][:test_ids] sia impostato sul tuo elenco di ID di test (che la risposta di Mohamed aiuterà). Così la vostra azione di controllo sarebbe simile a questa:

def update 
    package = Package.find(params[:id]) 
    package.update_attributes params[:package] 
end 

Questo aggiornerà tutto in una volta in una transazione/database di ActiveRecord. Ciò significa che se la convalida fallisce, tutte le modifiche verranno annullate, quindi non importa che i test siano stati salvati. Ulteriori informazioni sono here.

Inoltre, mi consiglia di chiamare tests.size anziché test_ids.count, poiché la sostituzione tende a generare una query migliore (o non è necessario andare al database).

+0

Fine.Ma c'è un problema quando si chiama update_attributes con parametro test_ids, esso solleverà un'eccezione invece di restituire vero o falso se la convalida fallisce in relazione alla validazione test_ids (metodo at_most_3_tests). Qualche suggerimento? Codice di esempio: if package.update_attributes params [: package] –

+0

Ho usato ** validates_associated: package ** in PackageTest model –

+0

validates_associated non dovrebbe generare un'eccezione per impostazione predefinita. Che errore stai ottenendo? – Ari

Problemi correlati