Rails 5 更新 has_many 通过关联模型
Rails 5 update has_many through associates models
我有以下型号
class TeamPlayer < ApplicationRecord
belongs_to :team
belongs_to :player
belongs_to :role
end
class Team < ApplicationRecord
has_many :team_players
has_many :players, :through => :team_players
end
class Role < ApplicationRecord
has_many :team_players
has_many :players, :through => :team_players
end
class Player < ApplicationRecord
has_many :team_players
has_many :teams, :through => :team_players
has_many :roles, :through => :team_players
end
基本上,我想为团队中的不同球员分配不同的角色。
id team_id player_id role_id
2 1 2 1
3 3 2 1
4 1 1 2
在我的 teams_controller.rb
中添加具有角色的新玩家、更新具有新角色的玩家以及从我的团队中删除该玩家应该是什么样子?
这只是一个可能解决方案的开始,它与添加了一些模型和数据库验证的解决方案非常相似。其中一些验证可确保每个 three-way 关系 (FilledTeamRole
) 的唯一性,因此需要处理尝试创建重复记录的错误,或者您可以过滤每个 [=] 的可能 ID 93=] 可以选择以便无法创建重复项。
一个完整的解决方案将取决于您希望 Team
、Player
和 Role
class 之间的其他关联,而不是需要所有三个的关联。例如,你是否 want/need Team
和 Player
之间的关联,其中仅存在这两个 class 之间的关系而无需 Role
(TeamPlayer
id: 1, team_id: 1, player_id: 1
)。如果需要这些关系,则需要额外的代码来实现这一点,我已经拥有并且可以作为建议提供。
就控制器的外观而言,您可以使用 filled_team_roles
控制器(或者创建一个仪表板控制器),提供实例变量 @teams
、@players
和 @roles
为表单中的每个 class 填充 drop-down 菜单,以创建 filled_team_roles
关系。您还可以在每个其他 classes 中包含其他表单,其中使用两个 drop-downs 而不是三个,第三个值是 class 的选定模型 ID,其控制器是在(例如 players_controller
中的 edit
操作与 team
和 role
的 drop-downs)
~/app/models/team.rb
class Team < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates :name, uniqueness: { scope: [:sport, :city] }
scope :by_name_asc, -> { order(name: :asc) }
end
~/app/models/player.rb
class Player < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates_uniqueness_of :ssn
scope :by_name_asc, -> { order(last_name: :asc, first_name: :asc) }
end
~/app/models/role.rb
class Role < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates_uniqueness_of :name
scope :by_name_asc, -> { order(name: :asc) }
end
~/app/models/filled_team_role.rb
class FilledTeamRole < ApplicationRecord
belongs_to :team
belongs_to :player
belongs_to :role
validates :team_id, presence: true
validates :player_id, presence: true
validates :role_id, presence: true
validates :team_id, uniqueness: { scope: [:player_id, :role_id] }
end
~/db/migrate/20170127041000_create_team.rb
class CreateTeam < ActiveRecord::Migration[5.0]
def change
create_table :teams do |t|
t.string :name
t.string :sport
t.string :city
t.string :state
t.string :country
t.timestamps null: false
end
add_index :teams, [:name, :sport, :city], unique: true
end
end
~/db/migrate/20170127041100_create_player.rb
class CreatePlayer < ActiveRecord::Migration[5.0]
def change
create_table :players do |t|
t.string :first_name
t.string :last_name, index: true
t.string :full_name_surname_first
t.string :ssn, index: { unique: true }
t.timestamps null: false
end
end
end
~/db/migrate/20170127041200_create_role.rb
class CreateRole < ActiveRecord::Migration[5.0]
def change
create_table :roles do |t|
t.string :name, index: { unique: true }
t.timestamps null: false
end
end
end
~/db/migrate/20170127051300_create_filled_team_role.rb
class CreateFilledTeamRole < ActiveRecord::Migration[5.0]
def change
create_table :filled_team_roles do |t|
t.timestamps null: false
t.references :team
t.references :role
t.references :player
end
add_index :filled_team_roles,
[:team_id, :player_id, :role_id],
unique: true,
name: 'index_filled_team_roles_unique_combination_of_foreign_keys'
end
end
~/db/seeds.rb
Team.create(name: 'Los Angeles Dodgers', sport: 'baseball', city: 'Los Angeles', state: 'CA', country: 'United States')
Team.create(name: 'New York Yankees', sport: 'baseball', city: 'New York', state: 'NY', country: 'United States')
Team.create(name: 'Chicago Cubs', sport: 'baseball', city: 'Chicago', state: 'IL', country: 'United States')
Team.create(name: 'St. Louis Cardinals', sport: 'baseball', city: 'St. Louis', state: 'MO', country: 'United States')
Player.create(first_name: 'Max', last_name: 'Walker', full_name_surname_first: 'Walker, Max', ssn: '123-45-6789')
Player.create(first_name: 'Homer', last_name: 'Winn', full_name_surname_first: 'Winn, Homer', ssn: '234-56-7890')
Player.create(first_name: 'Will', last_name: 'Steel', full_name_surname_first: 'Steel, Will', ssn: '345-67-8901')
Player.create(first_name: 'Lucky', last_name: 'Snag', full_name_surname_first: 'Snag, Lucky', ssn: '456-78-9012')
Role.create(name: 'pitcher')
Role.create(name: 'catcher')
Role.create(name: 'first baseman')
Role.create(name: 'second baseman')
Role.create(name: 'shortstop')
Role.create(name: 'third baseman')
Role.create(name: 'right fielder')
Role.create(name: 'center fielder')
Role.create(name: 'left fielder')
FilledTeamRole.create(team_id: 1, player_id: 1, role_id: 1)
FilledTeamRole.create(team_id: 2, player_id: 2, role_id: 2)
FilledTeamRole.create(team_id: 3, player_id: 3, role_id: 3)
FilledTeamRole.create(team_id: 4, player_id: 4, role_id: 4)
我有以下型号
class TeamPlayer < ApplicationRecord
belongs_to :team
belongs_to :player
belongs_to :role
end
class Team < ApplicationRecord
has_many :team_players
has_many :players, :through => :team_players
end
class Role < ApplicationRecord
has_many :team_players
has_many :players, :through => :team_players
end
class Player < ApplicationRecord
has_many :team_players
has_many :teams, :through => :team_players
has_many :roles, :through => :team_players
end
基本上,我想为团队中的不同球员分配不同的角色。
id team_id player_id role_id
2 1 2 1
3 3 2 1
4 1 1 2
在我的 teams_controller.rb
中添加具有角色的新玩家、更新具有新角色的玩家以及从我的团队中删除该玩家应该是什么样子?
这只是一个可能解决方案的开始,它与添加了一些模型和数据库验证的解决方案非常相似。其中一些验证可确保每个 three-way 关系 (FilledTeamRole
) 的唯一性,因此需要处理尝试创建重复记录的错误,或者您可以过滤每个 [=] 的可能 ID 93=] 可以选择以便无法创建重复项。
一个完整的解决方案将取决于您希望 Team
、Player
和 Role
class 之间的其他关联,而不是需要所有三个的关联。例如,你是否 want/need Team
和 Player
之间的关联,其中仅存在这两个 class 之间的关系而无需 Role
(TeamPlayer
id: 1, team_id: 1, player_id: 1
)。如果需要这些关系,则需要额外的代码来实现这一点,我已经拥有并且可以作为建议提供。
就控制器的外观而言,您可以使用 filled_team_roles
控制器(或者创建一个仪表板控制器),提供实例变量 @teams
、@players
和 @roles
为表单中的每个 class 填充 drop-down 菜单,以创建 filled_team_roles
关系。您还可以在每个其他 classes 中包含其他表单,其中使用两个 drop-downs 而不是三个,第三个值是 class 的选定模型 ID,其控制器是在(例如 players_controller
中的 edit
操作与 team
和 role
的 drop-downs)
~/app/models/team.rb
class Team < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates :name, uniqueness: { scope: [:sport, :city] }
scope :by_name_asc, -> { order(name: :asc) }
end
~/app/models/player.rb
class Player < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates_uniqueness_of :ssn
scope :by_name_asc, -> { order(last_name: :asc, first_name: :asc) }
end
~/app/models/role.rb
class Role < ApplicationRecord
has_many :filled_team_roles, dependent: :destroy
validates_uniqueness_of :name
scope :by_name_asc, -> { order(name: :asc) }
end
~/app/models/filled_team_role.rb
class FilledTeamRole < ApplicationRecord
belongs_to :team
belongs_to :player
belongs_to :role
validates :team_id, presence: true
validates :player_id, presence: true
validates :role_id, presence: true
validates :team_id, uniqueness: { scope: [:player_id, :role_id] }
end
~/db/migrate/20170127041000_create_team.rb
class CreateTeam < ActiveRecord::Migration[5.0]
def change
create_table :teams do |t|
t.string :name
t.string :sport
t.string :city
t.string :state
t.string :country
t.timestamps null: false
end
add_index :teams, [:name, :sport, :city], unique: true
end
end
~/db/migrate/20170127041100_create_player.rb
class CreatePlayer < ActiveRecord::Migration[5.0]
def change
create_table :players do |t|
t.string :first_name
t.string :last_name, index: true
t.string :full_name_surname_first
t.string :ssn, index: { unique: true }
t.timestamps null: false
end
end
end
~/db/migrate/20170127041200_create_role.rb
class CreateRole < ActiveRecord::Migration[5.0]
def change
create_table :roles do |t|
t.string :name, index: { unique: true }
t.timestamps null: false
end
end
end
~/db/migrate/20170127051300_create_filled_team_role.rb
class CreateFilledTeamRole < ActiveRecord::Migration[5.0]
def change
create_table :filled_team_roles do |t|
t.timestamps null: false
t.references :team
t.references :role
t.references :player
end
add_index :filled_team_roles,
[:team_id, :player_id, :role_id],
unique: true,
name: 'index_filled_team_roles_unique_combination_of_foreign_keys'
end
end
~/db/seeds.rb
Team.create(name: 'Los Angeles Dodgers', sport: 'baseball', city: 'Los Angeles', state: 'CA', country: 'United States')
Team.create(name: 'New York Yankees', sport: 'baseball', city: 'New York', state: 'NY', country: 'United States')
Team.create(name: 'Chicago Cubs', sport: 'baseball', city: 'Chicago', state: 'IL', country: 'United States')
Team.create(name: 'St. Louis Cardinals', sport: 'baseball', city: 'St. Louis', state: 'MO', country: 'United States')
Player.create(first_name: 'Max', last_name: 'Walker', full_name_surname_first: 'Walker, Max', ssn: '123-45-6789')
Player.create(first_name: 'Homer', last_name: 'Winn', full_name_surname_first: 'Winn, Homer', ssn: '234-56-7890')
Player.create(first_name: 'Will', last_name: 'Steel', full_name_surname_first: 'Steel, Will', ssn: '345-67-8901')
Player.create(first_name: 'Lucky', last_name: 'Snag', full_name_surname_first: 'Snag, Lucky', ssn: '456-78-9012')
Role.create(name: 'pitcher')
Role.create(name: 'catcher')
Role.create(name: 'first baseman')
Role.create(name: 'second baseman')
Role.create(name: 'shortstop')
Role.create(name: 'third baseman')
Role.create(name: 'right fielder')
Role.create(name: 'center fielder')
Role.create(name: 'left fielder')
FilledTeamRole.create(team_id: 1, player_id: 1, role_id: 1)
FilledTeamRole.create(team_id: 2, player_id: 2, role_id: 2)
FilledTeamRole.create(team_id: 3, player_id: 3, role_id: 3)
FilledTeamRole.create(team_id: 4, player_id: 4, role_id: 4)