2010-01-21 7 views
6

Tengo dos modelos con una relación de muchos a muchos usando has_and_belongs_to_many. De este modo:Cómo asociar un nuevo modelo con modelos existentes usando 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 

Si suponemos que ya he creado varias competiciones en la base de datos, cuando se crea un nuevo equipo, me gustaría usar una forma anidada para asociar el nuevo equipo con cualquier competición pertinentes.

Es en este punto en adelante que realmente necesito ayuda (¡he estado atascado en esto durante horas!) Y creo que mi código actual ya se ha equivocado, pero lo mostraré por si acaso:

class TeamsController < ApplicationController 
    def new 
    @team = Team.new 
    @competitions.all 
    @competitions.size.times {@team.competitions.build} 
    end 
    def create 
    @team = Team.new params[:team] 
    if @team.save 
     # .. usual if logic on save 
    end 
    end 
end 

Y la vista ... aquí es donde estoy realmente atascado, así que no publicaré mis esfuerzos hasta el momento. Lo que me gustaría es una lista de casillas de verificación para cada competencia para que el usuario pueda seleccionar las competencias apropiadas y dejar sin marcar aquellas que no lo son.

estoy realmente atascado con éste de manera apreciar cualquier apuntando en la dirección correcta que se puede brindar :)

Respuesta

4

El método has_and_belongs_to_many de unirse a los modelos juntos está en desuso en favor de la nueva has_many ...: a través de enfoque . Es muy difícil administrar los datos almacenados en una relación has_and_belongs_to_ many, ya que Rails no proporciona métodos predeterminados, pero el método through es un modelo de primera clase y se puede manipular como tal.

Lo que se refiere a su problema, es posible que desee para resolver de esta manera:

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 

Cuando se trata de la creación de los propios equipos, se debe estructurar su solicitud de manera que uno de los parámetros que recibe es enviado como una matriz. Por lo general, esto se hace especificando que todos los campos de casillas de verificación tengan el mismo nombre, como "competiciones []" y luego establezca el valor de cada casilla de verificación para ser el ID de la competencia. A continuación, el controlador podría ser algo como esto:

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 

Ajuste del estado de activada o desactivada para cada elemento en su casilla lista se hace por algo como:

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

Donde la 'competencia' es el que se repite.

Puede agregar y eliminar fácilmente elementos de su lista de competiciones, o simplemente volver a asignar la lista completa y Rails descubrirá las nuevas relaciones basadas en ella. Su método de actualización no se vería tan diferente del nuevo método, excepto que estaría utilizando atributos_actualización en lugar de nuevos.

+2

Gracias por su respuesta (y sugerencias para tomar un par de días para responder). Tu solución funciona bien, aunque tardé un poco en averiguar cómo crear el formulario. Para el beneficio de cualquier otra persona tropezando con esto, mientras que el formulario Team se genera utilizando form_for helper, para la parte de competencias creé manualmente las casillas de verificación como sigue: <% = check_box_tag "team [competitions] []", competition. id, @ team.competitions.include? (competition),: id => "team_competitions _ # {competition.id}"%> – aaronrussell

Cuestiones relacionadas