2017-01-27 20 views
2

я следующие моделиRails 5 обновления has_many через ассоциированные модели

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, чтобы добавить новый игрок с ролью, чтобы обновить плеер с новой ролью и удалить этот игрок из моей команды?

+0

Вопрос и комментарий: Как вы его настроили на данный момент, игрок может принадлежать нескольким командам. Так вы этого хотите? Если это так, поскольку игрок может также иметь несколько ролей, вам понадобится способ определить, в какой команде у игрока есть определенная роль. То, что приходит на ум, - это вложение атрибутов Role в Team и только создание роли в контексте команды. Я считаю, что если игрок может принадлежать только одной команде, то ваше решение немного более прямолинейно. – eggroll

+0

Но в этом дизайне игрок может принадлежать многим командам через ': team_players'. Например: 'Team A' выдает« Player 1' 'Team B', он по-прежнему принадлежит команде« A », но статус или роль изменились. – ln9187

ответ

1

Это только начало возможного решения, и оно очень похоже на то, что у вас есть, с добавленной валидностью модели и базы данных. Некоторые из этих валидаций обеспечивают уникальность каждой трехсторонней связи (FilledTeamRole), поэтому нужно либо обработать ошибку при попытке создать дублируемую запись, либо вы можете отфильтровать возможные идентификаторы каждого класса, который можно выбрать, чтобы дубликат не может быть создан.

Полное решение будет зависеть от того, какие другие ассоциации вы хотите между классами Team, Player и Role, отличными от тех, которые требуют всех трех. Например, вам нужна/нужна связь между Team и Player, где существует связь между этими двумя классами без необходимости Role (TeamPlayerid: 1, team_id: 1, player_id: 1). Если эти отношения желательны, то для этого потребуется дополнительный код, который у меня есть и могу предложить в качестве предложения.

Насколько то, что ваш контроллер будет выглядеть, вы можете использовать контроллер filled_team_roles (или, возможно, создать контроллер приборной панели), обеспечивают переменный экземпляр @teams, @players и @roles для заполнения раскрывающегося меню для каждого класса в форме создайте отношения filled_team_roles. Вы также можете иметь дополнительные формы в каждом из других классов, где с использованием двух выпадающих списков вместо трех с третьим значением выбранный идентификатор модели класса, в контроллере которого находится форма (например, действие edit в players_controller, спады для team и role)

~/приложение/модели/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 

~/приложение/модели/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 

~/приложение/модели/role.rb

class Role < ApplicationRecord 
    has_many :filled_team_roles, dependent: :destroy 
    validates_uniqueness_of :name 
    scope :by_name_asc, -> { order(name: :asc) } 
end 

~/приложение/модели/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 

~/дб/мигрировать/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.Р.Б.

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 

~/дБ/мигрировать/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 

~/дБ/мигрировать/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 

~/дБ/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) 
+0

Обратите внимание, что я сделал исправление в принятой версии ответа, заменив 'validates: team_id, уникальность: {scope: [: player_id,: position_id]}' в модели 'filled_team_role' с помощью' validates: team_id, уникальность: {scope: [: player_id,: role_id]} '. – eggroll