2010-01-21 4 views
6

Ich habe zwei Modelle mit einer Beziehung von vielen zu vielen mit has_and_belongs_to_many. Wie so:So verknüpfen Sie ein neues Modell mit vorhandenen Modellen mit has_and_belongs_to_many

class Competition < ActiveRecord::Base 
    has_and_belongs_to_many :teams 
    accepts_nested_attributes_for :teams 
end 

class Team < ActiveRecord::Base 
    has_and_belongs_to_many :competitions 
    accepts_nested_attributes_for :competitions 
end 

Wenn wir davon ausgehen, dass ich schon mehrere Wettbewerbe in der Datenbank erstellt habe, wenn ich ein neues Team zu erstellen, würde Ich mag eine verschachtelte Form verwenden, das neue Team mit allen relevanten Wettbewerben zu verknüpfen.

Es ist an diesem Punkt, dass ich wirklich Hilfe brauche (seit Stunden daran festhalten!) Und ich denke, mein bestehender Code ist schon in die falsche Richtung gegangen, aber ich werde es nur für den Fall zeigen:

Und die Aussicht ... das ist, wo ich wirklich feststecke, so werde ich beide meine Bemühungen bisher nicht veröffentlichen. Was ich möchte es eine Liste von Kontrollkästchen für jeden Wettbewerb, so dass der Benutzer nur auswählen kann, welche Wettbewerbe angemessen sind, und lassen Sie diejenigen deaktiviert, die nicht sind.

Ich bin wirklich stecken mit diesem so jede Zeige in die richtige Richtung schätzen Sie bieten kann :)

Antwort

4

Die has_and_belongs_to_many Methode von Modellen gemeinsam ist veraltet zugunsten des neuen has_many Beitritt ...: durch Annäherung . Es ist sehr schwierig, die in einer has_and_belongs_to_many-Beziehung gespeicherten Daten zu verwalten, da Rails keine Standardmethoden zur Verfügung stellt, aber die Methode: through ein erstklassiges Modell ist und als solches manipuliert werden kann.

Da es für Ihr Problem bezieht, können Sie es wie folgt lösen möchten:

class Competition < ActiveRecord::Base 
    has_many :participating_teams 
    has_many :teams, 
    :through => :participating_teams, 
    :source => :team 
end 

class Team < ActiveRecord::Base 
    has_many :participating_teams 
    has_many :competitions, 
    :through => :participating_teams, 
    :source => :competition 
end 

class ParticipatingTeam < ActiveRecord::Base 
    belongs_to :competition 
    belongs_to :team 
end 

Wenn es um die Schaffung von den Teams selbst kommt, sollten Sie Ihre Form so strukturieren, dass einer der Parameter, die Sie empfangen, gesendet als ein Array. In der Regel werden alle Kontrollkästchen mit dem gleichen Namen versehen, z. B. "Wettbewerbe []", und der Wert für jedes Kontrollkästchen als ID des Wettbewerbs festgelegt. Dann würde der Controller wie folgt aussehen:

class TeamsController < ApplicationController 
    before_filter :build_team, :only => [ :new, :create ] 

    def new 
    @competitions = Competitions.all 
    end 

    def create 
    @team.save! 

    # .. usual if logic on save 
    rescue ActiveRecord::RecordInvalid 
    new 
    render(:action => 'new') 
    end 

protected 
    def build_team 
    # Set default empty hash if this is a new call, or a create call 
    # with missing params. 
    params[:team] ||= { } 

    # NOTE: HashWithIndifferentAccess requires keys to be deleted by String 
    # name not Symbol. 
    competition_ids = params[:team].delete('competitions') 

    @team = Team.new(params[:team]) 

    @team.competitions = Competition.find_all_by_id(competition_ids) 
    end 
end 

Einstellen des Status aktiviert oder deaktiviert für jedes Element in Ihrem Check-Box-Eintrag durch so etwas wie getan wird:

checked = @team.competitions.include?(competition) 

Wo ‚Wettbewerb‘ ist der eine wird über iteriert.

Sie können einfach Elemente aus Ihrem Wettbewerb hinzufügen oder entfernen, oder einfach die gesamte Liste neu zuweisen und Rails wird die neuen Beziehungen basierend darauf herausfinden. Ihre Aktualisierungsmethode würde nicht von der neuen Methode abweichen, außer dass Sie update_attributes anstelle von new verwenden würden.

+2

Vielen Dank für Ihre Antwort (und ein paar Tage um zu antworten). Deine Lösung funktioniert gut, obwohl ich eine Weile gebraucht habe, um herauszufinden, wie man das Formular erstellt. Für den Fall, dass jemand darüber stolpert, während das Teamformular mit dem Helfer form_for generiert wird, habe ich für den Wettbewerbsteil die Checkboxen manuell so angelegt: <% = check_box_tag "team [competitions] []", competition. id, @ team.competitions.include? (Wettbewerb),: id => "team_competitions _ # {competition.id}"%> – aaronrussell

Verwandte Themen