I have a has_many :through association. Players have many Teams and Teams have many Players. The join model, Affiliation, belongs to Players and Teams, and also has a year
attribute to keep track of a player's team affiliation (or employment) from year to year.
I can't seem to figure out the right way to build an association based on the following rules:
- Create a new player.
- Associate a team that may be new or existing. So find it or create it, but only create it if the player is saved.
- The association may or may not include a year, but the association should only be created if the player and team are saved.
The Player model looks like:
class Player < ActiveRecord::Base
attr_accessible :name
has_many :affiliations, :dependent => :destroy
has_many :teams, :through => :affiliations
end
The Team model looks like:
class Team < ActiveRecord::Base
attr_accessible :city
has_many :affiliations, :dependent => :destroy
has_many :players, :through => :affiliations
end
The Affiliation model looks like:
class Affiliation < ActiveRecord::Base
attr_accessible :player_id, :team_id, :year
belongs_to :player
belongs_to :team
end
I have been successful at creating the association records without the join model attribute using a create action in the PlayersController that looks like:
class PlayersController < ApplicationController
def create
@player = Player.new(params[:player].except(:teams))
unless params[:player][:teams].blank?
params[:player][:teams].each do |team|
team_to_associate = Team.find_or_initialize_by_id(team[:id], team.except(:year)
@player.teams << team_to_associate
end
end
@player.save
respond_with @player
end
end
After creating a new player with two teams using params like:
{"player"=>{"name"=>"George Baker", "teams"=>[{"city"=>"Buffalo"}, {"city"=>"Detroit"}]}}
the database looks like:
players
id: 1, name: George Baker
teams
id: 1, city: Buffalo
id: 2, city: Seattle
affiliations
id: 1, player_id: 1, team_id: 1, year: null
id: 2, player_id: 1, team_id: 2, year: null
When I try to introduce the year, things fall apart. My most recent attempt at the create action in the PlayersController looks like:
class PlayersController < ApplicationController
def create
@player = Player.new(params[:player].except(:teams))
unless params[:player][:teams].blank?
params[:player][:teams].each do |team|
team_to_associate = Team.find_or_initialize_by_id(team[:id], team.except(:year)
// only additional line...
team_to_associate.affiliations.build({:year => team[:year]})
@player.teams << team_to_associate
end
end
@player.save
respond_with @player
end
end
Now, when creating a new player with two teams using params like:
{"player"=>{"name"=>"Bill Johnson", "teams"=>[{"id"=>"1"}, {"city"=>"Detroit", "year"=>"1999"}]}}
the database looks like:
players
id: 1, name: George Baker
id: 2, name: Bill Johnson
teams
id: 1, city: Buffalo
id: 2, city: Seattle
id: 3, city: Detroit
affiliations
id: 1, player_id: 1, team_id: 1, year: null
id: 2, player_id: 1, team_id: 2, year: null
id: 3, player_id: 2, team_id: 1, year: null
id: 4, player_id: null, team_id: 3, year: 1999
id: 5, player_id: 2, team_id: 3, year: null
So three records were created when only two should have been. The affiliation record id: 3 is correct. For id: 4, the player_id is missing. And for id: 5, the year is missing.
Obviously this is incorrect. Where am I going wrong?
Thanks