我有三个模型,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。
如何获得我想要的行为?
答案 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