2014-10-28 6 views
5

Gibt es eine Möglichkeit zu vermeiden, automatisch Objekt beim Zuweisen von Auflistungsattributen zu speichern (collection_singular_ids = IDs-Methode)?Rails 3 kann keine Validierung für persited Objekt durchführen, wenn Verwendung collection_singular_ids = IDs Methode

zum Beispiel habe ich das folgende Test- und Paketmodell, Paket hat viele Tests. Der Benutzer kann Paketbündel mit einer Anzahl von Tests erstellen.

Kein Problem für die Validierung, wenn Paketobjekt ist neue.

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 

Aber ich konnte nicht Methode getroffen at_most_3_tests mit beharrte Paketobjekt.

Tabellensatz Join wird sofort erstellt, wenn Test-IDs zuweisen

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] 

Client-Anforderung in der Dropdown-Schnittstelle für die Auswahl mehrerer Tests in verpackter Form und verwendet auch select2 jQuery-Plugin für Drop-down. Rhmtl Code sieht aus wie

<%= 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> 

Bitte mir helfen, dieses Problem zu beheben.

Antwort

5

Für Limit Anzahl Zuordnungen

Sie können die folgenden Validierungen wie die folgenden statt Ihrer Methode verwenden:

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

für mehr mit wählen

ich dieses Problem habe vorher, und ich löste es mit dem folgenden Code:

Ich denke, options_from_collection_for_select, lesen Sie Kategorien von Postbeispiel aus dieser link kann Ihnen helfen.

Für Validation

I verwendet validates_associated, wie die folgenden:

validates_associated :tests 

Für bekommen die alten Attribute für persistente Objekt

Sie reload für aktiven Datensatz als die verwenden können, folgende:

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] 

Oder Sie können die Validierung von Paketobjekt überprüfen, wenn es falsch reload ist es:

unless package.valid? 
    package.reload 
end 
+0

Ich kann package.valid nicht aufrufen? weil bei der Zuweisung von Array von IDs dann automatisch Aktion speichern ausgelöst wird. Zum Beispiel package.test_ids = [1,2,3,4,5] –

+0

@ManivannanJeganathan Ich aktualisiere meine Antwort, um diese Validierung zu verwenden 'has_many: tests,: length => {: maximum => 3}' –

+0

Meine Validierung ist nicht nur basierend auf Länge. Ich habe nur Beispielcode angegeben. params [: package] sollte immer test_ids-Parameter wie {: cost => 3.4,: test_ids => [1,2,3,4,5]} haben. Ich muss einfach die Validierungsmethode im Paketmodell treffen und das Formular rendern, wenn die Validierung fehlschlägt. Ich kann Validierungsmethode mit Hilfe Ihrer Antwort schlagen, indem ich "' validates_associated: package''' im PackageTest-Modell aufruft. Aber Wenn die Validierung im Zusammenhang mit der Validierung von test_ids fehlschlägt, wird die Ausnahme ausgelöst, anstatt wahr oder falsch zurückzugeben. Ex-Code '' 'if @ package.update_attributes params [: Paket] else rendern" form "' '' –

3

Wenn Sie manuell die test_ids in der Steuerung zuweisen sind, würde ich vorschlagen das gesamte Objekt mit verschachtelten Attributen zu aktualisieren stattdessen.Dies setzt voraus, dass params[:package][:test_ids] auf Ihre Liste von Test-IDs gesetzt ist (worauf Mohameds Antwort hilft). So Ihre Controller-Aktion würde wie folgt aussehen:

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

Dies wird in einer Activerecord/Datenbanktransaktion, alles auf einmal aktualisieren. Dies bedeutet, dass bei einer fehlgeschlagenen Validierung alle Änderungen rückgängig gemacht werden. Daher spielt es keine Rolle, dass die Tests gespeichert wurden. Weitere Informationen sind here.

Auch würde ich empfehlen, tests.size anstelle von test_ids.count zu nennen, da der Ersatz tendenziell eine bessere Abfrage erzeugen wird (oder nicht in die Datenbank gehen muss).

+0

Fine.But gibt es Problem beim Aufrufen von update_attributes mit test_ids -Parameter, es wird Ausnahme auslösen, anstatt wahr oder falsch, wenn Validierung im Zusammenhang mit test_ids Validierung (At_most_3_tests-Methode) fehlschlägt. Irgendein Vorschlag? Beispielcode: if package.update_attributes params [: package] –

+0

Ich habe ** validates_associated: package ** im PackageTest-Modell verwendet –

+0

validates_associated sollte standardmäßig keine Ausnahme auslösen. Welchen Fehler bekommst du? – Ari