钢轨在3的has_many不正确的数据库记录:通过协会 [英] incorrect database records created for rails 3 has_many :through association
问题描述
我有一个的has_many:通过关联。玩家有很多球队和球队有很多球员。联接模型,隶属关系,属于球员和球队,并且还具有年
属性来跟踪一名球员的球队的关系(或就业)每年的。
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:
- 创建一个新的球员。
- 关联一个团队,可能是新的或现有的。所以找到它或创建它,但只有创建它,如果球员被保存。
- 的关联可以或可以不包括一年,但是,如果播放器和团队都保存在关联应该只被创建。
玩家模型如下:
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
我已经成功地使用看起来像PlayersController创建操作,而不加入模型属性创建关联记录:
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
创建使用PARAMS就像两支球队一个新的球员之后:
After creating a new player with two teams using params like:
{"player"=>{"name"=>"George Baker", "teams"=>[{"city"=>"Buffalo"}, {"city"=>"Detroit"}]}}
数据库如下:
玩家
ID:1,名称:乔治贝克
id: 1, name: George Baker
小组
ID:1,城市:布法罗
id: 1, city: Buffalo
ID:2,城市:西雅图
id: 2, city: Seattle
隶属关系
ID:1,player_id:1,TEAM_ID:1,年:空
id: 1, player_id: 1, team_id: 1, year: null
ID:2,player_id:1,TEAM_ID:2年:空
id: 2, player_id: 1, team_id: 2, year: null
当我尝试引进这一年,事情土崩瓦解。我最近在该PlayersController创建操作的尝试是这样的:
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
现在,使用像PARAMS两队创建一个新的播放器时:
Now, when creating a new player with two teams using params like:
{"player"=>{"name"=>"Bill Johnson", "teams"=>[{"id"=>"1"}, {"city"=>"Detroit", "year"=>"1999"}]}}
数据库如下:
玩家
ID:1,名称:乔治贝克
id: 1, name: George Baker
ID:2,名称:比尔·约翰逊
id: 2, name: Bill Johnson
小组
ID:1,城市:布法罗
id: 1, city: Buffalo
ID:2,城市:西雅图
id: 2, city: Seattle
ID:3,城市:底特律
id: 3, city: Detroit
隶属关系
ID:1,player_id:1,TEAM_ID:1,年:空
id: 1, player_id: 1, team_id: 1, year: null
ID:2,player_id:1,TEAM_ID:2年:空
id: 2, player_id: 1, team_id: 2, year: null
ID:3,player_id:2,TEAM_ID:1,年:空
id: 3, player_id: 2, team_id: 1, year: null
ID:4,player_id:空,TEAM_ID:3年:1999
id: 4, player_id: null, team_id: 3, year: 1999
ID:5,player_id:2,TEAM_ID:3年:空
id: 5, player_id: 2, team_id: 3, year: null
当只有两个应该已经建立,因此三个记录。隶属关系记录ID:3是正确的。对于ID:4,player_id缺失。而对于ID:5,今年是缺少
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?
感谢
推荐答案
修改
好吧,我想我有一个更好的解决方案。据我所知,你不能在深度的两个层面(尽管你可以测试它,也许它的工作原理)使用嵌套的属性,但没有prevents我们的模拟的这种行为:
Ok, i think i have a better solution. AFAIK, you can't use nested attributes on two levels of depth (though you could test it, maybe it works), but nothing prevents us to simulate this behavior :
class Player < ActiveRecord::Base
has_many :affiliations
has_many :teams, through: :affiliations
accespts_nested_attributes_for :affiliations, allow_destroy: true
end
class Affiliation < ActiveRecord::Base
belongs_to :player
belongs_to :team
validates :player, presence: true
validates :team, presence: true
attr_accessor :team_attributes
before_validation :link_team_for_nested_assignment
def link_team_for_nested_assignment
return true unless team.blank?
self.team = Team.find_or_create_by_id( team_attributes )
end
现在,这样做的:
@player = Player.new(
name: 'Bill Johnson',
affiliations_attributes: [
{year: 1999, team_attributes: {id: 1, city: 'Detroit}},
{team_attributes: {city: 'Somewhere else'}}
]
)
@player.save
应该创建所有必需的记录,并在出现问题时仍然回滚一切(因为保存
本身已经是包裹在一个事务)。作为奖励,所有的错误将关联到 @player
!
should create all the required records, and still rollback everything in case of problems (because the save
itself is already wrapped in a transaction). As a bonus, all the errors will be associated to @player
!
<击>这个怎么样?
class PlayersController < ApplicationController
def create
ActiveRecord::Base.transaction do
@player = Player.new(params[:player].except(:teams))
raise ActiveRecord::Rollback unless @player.save # first check
unless params[:player][:teams].blank?
@teams = []
params[:player][:teams].each do |team|
team_to_associate = Team.find_or_initialize_by_id(team[:id], team.except(:year))
raise ActiveRecord::Rollback unless team_to_associate.save # second check
if team[:year]
affiliation = team_to_associate.affiliations.build(player: @player, year: team[:year])
raise ActiveRecord::Rollback unless affiliation.save # third check
end
@teams << team_to_associate # keep the object so we have access to errors
end
end
end
flash[:notice] = "ok"
rescue ActiveRecord::Rollback => e
flash[:alert] = "nope"
ensure
respond_with @group
end
end
击>
这篇关于钢轨在3的has_many不正确的数据库记录:通过协会的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!