Использование Rails для правильного моделирования с has_many: through и assign_to - PullRequest
1 голос
/ 19 июля 2011

Я пытаюсь найти лучший способ определения моделей для команды / члена / человека, где человек может быть членом многих команд, а команда может иметь много членов.Наряду с «членскими» отношениями является должность, которую человек занимает в команде.В команде также должен быть ровно один главный тренер и один помощник тренера.Человек может быть главным / помощником тренера для более чем одной команды.

Ниже моя текущая (бесполезная) попытка:

class Team < ActiveRecord::Base
  has_many :members
  has_many :people, :through => :members
  belongs_to :head_coach :class => 'Person' 
  belongs_to :assistant_coach :class => 'Person'
end

class Person < ActiveRecord::Base
  has_many :teams
  has_many :teams, :through => :members
end

class Member < ActiveRecord::Base
  belongs_to :team
  belongs_to :person
  # has a "position" which is a string
end

Этот подход вызывает у меня две проблемы:

  1. Команда принадлежит: assistant_coach не работает.Возможно, это должен быть has_one, но тогда я не уверен, что имеет смысл помещать own_to в Person (я хочу FK в Team to Person).Приведенный ниже пример показывает, что то, как я его настроил, не работает с ActiveRecord:

    irb(main):006:0> t = Team.find(1)
    => #<Team id: 1, name: "Champs", created_at: "2011-07-18 01:50:56", updated_at: "2011-07-19 01:47:26", head_coach: nil> 
    irb(main):007:0> t.head_coach
    => nil
    irb(main):008:0> t.head_coach = Person.find(1)
    => #<Person id: 1, name: "Chris", created_at: "2011-07-18 01:52:34", updated_at: "2011-07-18 01:52:34">
    irb(main):009:0> t.save
    => true
    irb(main):010:0> t.head_coach
    => #<Person id: 1, name: "Chris", created_at: "2011-07-18 01:52:34", updated_at: "2011-07-18 01:52:34">
    irb(main):011:0> Team.find(1).head_coach
    => nil
    
  2. Кажется, что has_many: through работает, но я не нашел хорошего способаперечислить позиции для каждого человека в команде.Это моя текущая попытка в представлении:

    <% @team.people.each do |person| %>
      <%= person.name +" "+ @team.members.find_by_person_id(person).position %>
    

Есть ли в целом лучший подход к представлению этих отношений?

Спасибо за помощь!

-Крис

Ответы [ 2 ]

0 голосов
/ 29 июля 2011

В итоге я использовал следующий подход, используя явный ключ foreign_key, который работает нормально.

class Team < ActiveRecord::Base
  has_many :members
  has_many :people, :through => :members
  belongs_to :head_coach, :class => 'Person', :foreign_key head_coach_id 
  belongs_to :assistant_coach, :class => 'Person', :foreign_key assistant_coach_id
end

class Person < ActiveRecord::Base
  has_many :teams, :through => :members

end

class Member < ActiveRecord::Base
  belongs_to :team
  belongs_to :person
  # has a "position" which is a string
end

Единственный недостаток на сегодняшний день - я не смог заставить автоматически загружать внешние ключи вконтроллер.Мне нужно добавить такой код, чтобы сохранить ассоциации:

# POST /teams
def create
  @team = Team.new
  @team.head_coach = Person.find(params[:head_coach])
  @team.assistant_coach = Person.find(params[:assistant_coach])

  ....
0 голосов
/ 19 июля 2011

Не могли бы вы иметь логическое поле для head_coach и assistant_coach в своей таблице участников и использовать проверочное уникальное правило с областью действия.

EG Добавить в таблицу участников

is_head_coach:boolean
is_assistant_coach:boolean 

Теперь в вашей модели участника есть

validates_uniqueness_of :is_head_coach, :scope => [:team_id, :person_id]
validates_uniqueness_of :is_assistant_coach, :scope => [:team_id, :person_id]

Тогда вы могли бы использовать несколько именованных областей в модели человека или команды, чтобы найти head_coach.

Что касается перечисления всех позиций, которые вы не могли использовать:

@team.members.each do |member|
   "#{member.person.name} #{member.position}"

Если вы хотите отсортировать их определенным образом, возможно, вы могли бы добавить поле с именем sort_order: integer к таблице членов и отсортировать по нему.

Обновление:

Я понимаю, что приведенное выше решение не является масштабируемым. Как насчет того, чтобы использовать поле позиции в модели члена и создать для него область видимости, называемую «область действия», например:

scope :head_coach, lambda { where('position = 'head coach') }

Тогда вы можете использовать что-то вроде:

team.members.head_coach

Вы можете пойти еще дальше с этой областью

scope :get_position, lambda{|pos| where('position = ?', pos)}

и используйте

team.members.get_position('head_coach')

Вы могли бы написать собственный метод проверки, чтобы проверить, что вы в конечном итоге используете head_coach для каждой команды и т. Д.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...