我有一个has_many:通过关联。球员有很多球队,球队有很多球员。联盟模式Affiliation属于玩家和团队,并且还具有year
属性,用于跟踪玩家每年的团队归属(或就业)。
我似乎无法根据以下规则找出构建关联的正确方法:
播放器模型如下:
class Player < ActiveRecord::Base
attr_accessible :name
has_many :affiliations, :dependent => :destroy
has_many :teams, :through => :affiliations
end
Team模型如下:
class Team < ActiveRecord::Base
attr_accessible :city
has_many :affiliations, :dependent => :destroy
has_many :players, :through => :affiliations
end
Affiliation模型如下:
class Affiliation < ActiveRecord::Base
attr_accessible :player_id, :team_id, :year
belongs_to :player
belongs_to :team
end
我已成功使用PlayersController中的创建操作创建没有连接模型属性的关联记录,如下所示:
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
创建了一个新球员,其中两支球队使用了诸如以下的参数:
{"player"=>{"name"=>"George Baker", "teams"=>[{"city"=>"Buffalo"}, {"city"=>"Detroit"}]}}
数据库看起来像:
玩家
id:1,姓名:George Baker
队
id:1,city:Buffalo
id:2,city:Seattle
的隶属关系
id:1,player_id:1,team_id:1,year:null
id:2,player_id:1,team_id:2,year:null
当我试图介绍这一年时,情况就会崩溃。我最近在PlayersController中尝试创建动作的尝试如下:
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,如:
{"player"=>{"name"=>"Bill Johnson", "teams"=>[{"id"=>"1"}, {"city"=>"Detroit", "year"=>"1999"}]}}
数据库看起来像:
玩家
id:1,姓名:George Baker
id:2,姓名:Bill Johnson
队
id:1,city:Buffalo
id:2,city:Seattle
id:3,城市:底特律
的隶属关系
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
因此只创建了两个记录。从属关系记录ID:3是正确的。对于id:4,缺少player_id。对于身份证:5,这一年不见了。
显然这是不正确的。我哪里错了?
由于
答案 0 :(得分:0)
修改
好的,我想我有更好的解决方案。 AFAIK,你不能在两个深度级别上使用嵌套属性(虽然你可以测试它,也许它可以工作),但没有什么能阻止我们模拟这种行为:
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
应创建所有必需的记录,并在出现问题时仍然回滚所有内容(因为save
本身已经包含在事务中)。作为奖励,所有错误都将与@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
击> <击> 撞击>
答案 1 :(得分:0)
此解决方案最终为我工作。但是,如果有人将此代码用于他们自己的项目,请知道除了创建之外我还没有测试过任何其他操作。我确信,一旦我处理了阅读,更新和删除,其中一些会改变。
class Player < ActiveRecord::Base
attr_accessible :name
has_many :affiliations, :dependent => :destroy
has_many :teams, :through => :affiliations
accepts_nested_attributes_for :affiliations, :allow_destroy => true
attr_accessible :affiliations_attributes
end
class Team < ActiveRecord::Base
attr_accessible :city
has_many :affiliations, :dependent => :destroy
has_many :players, :through => :affiliations
end
class Affiliation < ActiveRecord::Base
attr_accessible :player_id, :team_id, :team_attributes, :year
belongs_to :player
belongs_to :team
accepts_nested_attributes_for :team
def team_attributes=(team_attributes)
self.team = Team.find_by_id(team_attributes[:id])
self.team = Team.new(team_attributes.except(:id)) if self.team.blank?
end
end
class PlayersController < ApplicationController
def create
player_params = params[:player].except(:teams)
affiliation_params = []
unless params[:player][:teams].blank?
params[:player][:teams].each do |team|
affiliation = {}
affiliation[:year] = team[:year] unless team[:year].blank?
affiliation[:team_attributes] = team.except(:year)
affiliation_params << affiliation
end
end
player_params[:affiliation_attributes] = affiliation_params unless affiliation_params.blank?
@player = Player.new(player_params)
@player.save
respond_with @player
end
end