使用嵌套属性保存一对多模型

时间:2014-03-08 15:20:12

标签: ruby-on-rails ruby-on-rails-4

使用Rails 4和Ruby 2.1。

假设我有两个模型,团队和玩家。它们看起来像这样:

team.rb:

# == Schema Information
#
# Table name: teams
#
#  id         :integer          not null, primary key
#  name       :string(255)
#  created_at :datetime
#  updated_at :datetime
#

class Team < ActiveRecord::Base
    has_many :players

    accepts_nested_attributes_for :players
end

player.rb:

# == Schema Information
#
# Table name: players
#
#  id         :integer          not null, primary key
#  name       :string(255)
#  team_id    :integer
#  created_at :datetime
#  updated_at :datetime
#

class Player < ActiveRecord::Base
    belongs_to :team
end

超级简单。我可以毫无困难地做到以下几点:

> params = { team: {
>       name: "Foo", players_attributes: [
>         {name: "Bar"}
>       ]
>     }}
> team = Team.new(params[:team]) # => #<Team id: nil, name: "Foo", created_at: nil, updated_at: nil> 
> team.save # => true
> team.players.first.name # => "Bar"

好。现在假设我更新了Player模型,以便在没有属于团队的情况下创建一个Player:

player.rb:

# == Schema Information
#
# Table name: players
#
#  id         :integer          not null, primary key
#  name       :string(255)
#  team_id    :integer
#  created_at :datetime
#  updated_at :datetime
#

class Player < ActiveRecord::Base
    belongs_to :team

    validates_presence_of :team
end

现在,当我尝试同样的事情时:

> params = { team: {
>       name: "Foo", players_attributes: [
>         {name: "Bar"}
>       ]
>     }}
> team = Team.new(params[:team]) # => #<Team id: nil, name: "Foo", created_at: nil, updated_at: nil> 
> team.save # => false
> team.errors # => #<ActiveModel::Errors:0x00000002bd13f0 @base=#<Team id: nil, name: "Foo", created_at: nil, updated_at: nil>, @messages={:"players.team"=>["can't be blank"]}>

如果没有玩家要求的团队,team_id显然是使用嵌套属性设置的。但是,一旦我需要它,验证在它有机会被设置之前就会破灭。我做错了吗?

1 个答案:

答案 0 :(得分:5)

替换

class Team < ActiveRecord::Base
  has_many :players
  accepts_nested_attributes_for :players
end

class Player < ActiveRecord::Base
  belongs_to :team
  validates_presence_of :team
end

使用

class Team < ActiveRecord::Base
  has_many :players, inverse_of: :team
  accepts_nested_attributes_for :players
end

class Player < ActiveRecord::Base
  belongs_to :team, inverse_of: :players
  validates_presence_of :team
end

在关联中添加inverse_of选项。