2016-03-24 4 views
1

Ich verwende die . Ich habe die folgenden Verbänden teams ein contact haben Assoziationen mehrere zu ermöglichen:Nested_form_fields zeigen vorhandene has_many verschachtelte Felder bei Validierungsfehler

#models/contact.rb 
class Contact < ActiveRecord::Base 
    has_many :contacts_teams 
    has_many :teams, through: :contacts 

    accepts_nested_attributes_for :contacts_teams, allow_destroy: true 
end 

#models/contacts_team.rb 
class ContactsTeam < ActiveRecord::Base 
    belongs_to :contact 
    belongs_to :team 
end 

#models/team.rb 
class Team < ActiveRecord::Base 
    has_many :contacts_team 
    has_many :contacts, through: :contacts_teams 
end 

Ein Kontakt immer mindestens eine team haben muss. Ich habe eine benutzerdefinierte Validierung erstellt, die darauf prüft, ob der Benutzer eine neue contact erstellt oder eine vorhandene contact aktualisiert.

#custom validation within models/contact.rb 
class Contact < ActiveRecord::Base 
    ... 
    validate :at_least_one_contacts_team 

    private 
    def at_least_one_contacts_team 
    # when creating a new contact: making sure at least one team exists 
    return errors.add :base, "Must have at least one Team" unless contacts_teams.length > 0 

    # when updating an existing contact: Making sure that at least one team would exist 
    return errors.add :base, "Must have at least one Team" if contacts_teams.reject{|contacts_team| contacts_team._destroy == true}.empty? 
    end   
end 

Es funktioniert zum größten Teil. Es gibt jedoch einen Randfall beim Aktualisieren eines vorhandenen Kontaktteams. Hier habe ich einen Kontakt bin zu aktualisieren und es zeigt, dass sie zwei vorhandenen zugehörigen Teams:

existing teams

Der Benutzer klickt auf das X neben jedem Team, um sie zu löschen, so dass sie nicht mehr zeigen, auf der Seite, und dann klickt der Benutzer aktualisieren, diese Änderungen in Kraft zu setzen:

clicks the x's next to each contact

associated teams marked for deletion and don't show

submits changes

Die Überprüfung schlägt fehl, da der Benutzer versucht hat, alle zugehörigen Teams zu löschen. Es zeigt, richtig die Validierung Fehlermeldung:

error message

jedoch das Problem, dass das Formular nicht die vorhandenen zugehörigen Teams nicht erneut anzeigen! Diese Verbände haben noch nicht gelöscht wurden, so sollten sie noch zeigen:

Not showing existing team associations after validation fails

Wie kann ich bestehende Team Verbände nach Validierungen fehlschlagen, wenn ein bestehenden Kontakt zu aktualisieren?

Ich habe versucht, alle _destroy Flags in der Hoffnung, dass damit die assoziierten Teams zu zeigen. Leider hat es nicht den Trick:

# block run when update validation fails 
else 
    params[:contact][:contacts_teams_attributes].each do |k,v| 
    v.delete_if{|k,v| k == "_destroy" && v == "1"} 
    end 
    render :edit 
end 

Ich denke, dass die Seite der nested_form_fields' JavaScript ist Erinnerung, die zuvor Lauf war. Es erinnert sich also daran, dass die Teams zum Löschen markiert wurden, also werden sie nicht gerendert. Ich weiß nicht, wie man das Javascript zurücksetzt, es sei denn, ich mache eine redirect, in diesem Fall werden alle Überprüfungsfehler nicht mehr gezeigt.

Vielen Dank im Voraus!

+0

Sie könnten senden Sie das Formular ajax und ersetzen Sie einfach den Team-Bereich, wenn es Fehler gibt, oder alternativ eine JavaScript-Vorlage als Antwort in der Update-Methode in Ihrem Controller, die das gleiche tut - rendern nur den Abschnitt der Seite mit den Team-Auswahlfeldern – mgidea

Antwort

0

Hier ist die Antwort.Ich änderte den Namen der benutzerdefinierten Validierung innerhalb der Contact Modell, so dass die Fehlermeldung Sinn machen würde:

class Contact < ActiveRecord::Base 

    accepts_nested_attributes_for :contacts_teams, allow_destroy: true 
    validate :at_least_one_contacts_team 

    private 

    def at_least_one_contacts_team 
    return errors.add :A_Team, "must be present" unless contacts_teams.length > 0 
    return errors.add :A_Team, "must be present" if contacts_teams.reject{|contacts_team| contacts_team._destroy == true}.empty? 
    end 
end 

Und dann innerhalb der update Wirkung des ContactsController: durch

def update 
    authorize @contact 
    if @contact.update(contact_params) 
    redirect_to(some_path), success: 'Updated Successfully.' 
    else 
    # This next line is what makes it work as expected for that edge case 
    @contact.contacts_teams.reload if @contact.errors.keys.include?(:A_Team) 
    render :edit 
    end 
end