【问题标题】:validates_uniqueness_of fails when saving directly on the join model直接保存在连接模型上时,validates_uniqueness_of 失败
【发布时间】:2014-02-06 10:32:01
【问题描述】:

我有三个模型,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。

如何获得我想要的行为?

【问题讨论】:

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


【解决方案1】:

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

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

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-05-09
    • 1970-01-01
    • 2015-04-03
    • 1970-01-01
    • 1970-01-01
    • 2014-02-26
    相关资源
    最近更新 更多