直接在连接模型上保存时,validates_uniqueness_of失败

时间:2014-02-06 10:32:02

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

我有三个模型,Team,Player和TeamMembership。 TeamMembership定义了Team和Player之间的多对多关系。创建新团队时,用户会获得11个下拉菜单,每个菜单包含所有可用的玩家。但是,玩家只能拥有一个团队成员资格,这就是我想要验证的内容。

class Player < ActiveRecord::Base
  has_many :team_memberships
  has_many :teams, :through => :team_memberships
end

class Team < ActiveRecord::Base
  has_many :team_memberships
  has_many :players, :through => :team_memberships
  accepts_nested_attributes_for :players, :team_memberships
  validates_associated :team_memberships
end

class TeamMembership < ActiveRecord::Base
  belongs_to :team
  belongs_to :player
  validates_uniqueness_of :player_id, scope: :team_id
end

# GET /teams/new
def new
  @team = Team.new
  11.times { @team.team_memberships.build }
end

<%= f.fields_for :team_memberships do |team_memberships_form| %>
  <%= team_memberships_form.label :player_id %>
  <%= team_memberships_form.select(:player_id, options_from_collection_for_select(@Player.available, :id, :name)) %>
  <br />
<% end %>

尝试创建新团队时,开发日志中会显示以下内容。 (为简洁起见,只编辑了3名球员)

Started POST "/teams" for 127.0.0.1 at 2014-02-06 10:48:40 +0100
Processing by FantasyTeamsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"OwP+nfksvaD0WTQdGjqF5p/shzkiaAodigbFTC6PDD0=", "team"=>{"name"=>"asd", "tournament_id"=>"1", "team_memberships_attributes"=>{"0"=>{"player_id"=>"12"}, "1"=>{"player_id"=>"12"}, "2"=>{"player_id"=>"12"}, "3"=>{"player_id"=>"12"}}}, "commit"=>"Create Fantasy team"}
  User Load (0.6ms)  SELECT "users".* FROM "users" WHERE "users"."id" = 1 ORDER BY "users"."id" ASC LIMIT 1
  Role Exists (0.3ms)  SELECT 1 AS one FROM "roles" INNER JOIN "users_roles" ON "roles"."id" = "users_roles"."role_id" WHERE "users_roles"."user_id" = $1 AND "roles"."name" = 'admin' LIMIT 1  [["user_id", 1]](0.3ms)  BEGIN
  FantasyTeamMembership Exists (0.5ms)  SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
  CACHE (0.0ms)  SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
  CACHE (0.0ms)  SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
  CACHE (0.0ms)  SELECT 1 AS one FROM "team_memberships" WHERE ("team_memberships"."player_id" = 12 AND "team_memberships"."team_id" IS NULL) LIMIT 1
  SQL (0.5ms)  INSERT INTO "teams" ("created_at", "name", "tournament_id", "updated_at", "user_id") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["created_at", Thu, 06 Feb 2014 09:48:40 UTC +00:00], ["name", "asd"], ["tournament_id", 1], ["updated_at", Thu, 06 Feb 2014 09:48:40 UTC +00:00], ["user_id", 1]]
  SQL (0.4ms)  INSERT INTO "team_memberships" ("team_id", "player_id") VALUES ($1, $2) RETURNING "id"  [["team_id", 8], ["player_id", 12]]
  SQL (0.3ms)  INSERT INTO "team_memberships" ("team_id", "player_id") VALUES ($1, $2) RETURNING "id"  [["team_id", 8], ["player_id", 12]]
  SQL (0.3ms)  INSERT INTO "team_memberships" ("team_id", "player_id") VALUES ($1, $2) RETURNING "id"  [["team_id", 8], ["player_id", 12]]
   (14.7ms)  COMMIT
Redirected to http://lolhost:3000/teams/8
Completed 302 Found in 111ms (ActiveRecord: 34.3ms)

可以看出,由于我通过accepts_nested_attributes_for保存记录的方式,验证并不反映将运行的实际SQL。

如何获得我想要的行为?

1 个答案:

答案 0 :(得分:0)

通过向团队模型添加自定义验证方法来解决此问题。

validate :unique_players

def unique_players
  player_ids = team_memberships.map { |ft| ft.player_id }
  if player_ids != player_ids.uniq
    errors.add(:team_memberships, "must have unique players.")
  end
end