Rails 3: Должен ли я использовать STI или просто дополнительный столбец? (ищу совета)

#ruby-on-rails-3 #polymorphism #sti

#ruby-on-rails-3 #полиморфизм #sti

Вопрос:

Я работаю над проектом (Rails 3.0.3), где, я думаю, мне может понадобиться использовать STI, но я не уверен, должен ли я просто добавить дополнительный столбец в таблицу и покончить с этим.

В моей объектной модели (для игровой системы) У меня есть игроки (которые принадлежат агентствам) и владельцы (которые владеют агентствами).

И игроки, и владельцы принадлежат агентам, которые являются учетной записью пользователя, поэтому агент может быть игроком и / или владельцем во многих агентствах.

Я должен был назвать агента ‘user’ вместо этого, упс. Итак, у меня есть это:

 class Agency < ActiveRecord::Base
  has_many :players, :class_name => "Player", :foreign_key => "agency_id"
  has_many :agents, :through => :players, :source => :agent_id
  has_one :owner, :class_name => "Owner", :foreign_key => "agency_id"
end

class Player < ActiveRecord::Base
  belongs_to :agency, :class_name => "Agency", :foreign_key => "agency_id"
  belongs_to :agent, :class_name => "Agent", :foreign_key => "agent_id"
end

class Owner < ActiveRecord::Base
  belongs_to :agency, :class_name => "Agency", :foreign_key => "agency_id"
  belongs_to :agent, :class_name => "Agent", :foreign_key => "agent_id"
end
  

Игрок и владелец имеют абсолютно одинаковые атрибуты, единственное различие между ними заключается в том, что у владельца другие отношения с агентством, чем у Игрока (владелец владеет агентством, у Агентства только один владелец, но много игроков).

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

С точки зрения чистой ООП, Owner является подклассом Player (или, Owner и Player оба являются подклассами какого-то неопределенного класса, такого как Participant или что-то в этом роде), но при учете постоянства кажется, что дизайн базы данных с отдельными таблицами players и owners является плохим.

Моей первой мыслью было провести рефакторинг и использовать STI и либо сделать Owner подклассом Player, либо ввести новый базовый класс, а затем подклассы Owner и Player.

Моя другая мысль заключалась в том, что я мог бы просто добавить столбец boolean / tinyint в Player с именем is_owner, но я могу предвидеть, что это потенциально приведет к некоторому неприятному представлению и коду контроллера.

Мне было интересно, сталкивался ли кто-нибудь с подобными обстоятельствами и, возможно, имеет какой-либо совет или мог бы указать мне на какие-нибудь хорошие онлайн-ресурсы, чтобы прочитать о STI?

Комментарии:

1. Ps. Я не думаю, что вам нужно :class_name => and :foreign_key => для кода в классах Player и Owner .

2. Ах да, вы правы. Они были оставлены по умолчанию Textmate. Спасибо, что указали на это.

Ответ №1:

Возможно, вам следует думать о Player и Owner как об отношениях между Agent и Agency . Итак, Agent владеет Agency и Agent играет в игры с an Agency . Следовательно, вы могли бы ввести концепцию роли и, следовательно, модели, Role от которой Player наследуются и Owner . Вопрос в том, хотели ли вы когда-нибудь использовать Role модель? Или ваше приложение предназначено для владельцев и игроков, и за исключением некоторых общих атрибутов, это две совершенно разные вещи?

Если это две разные вещи, то вы должны создать для них две разные модели. Если у вас есть некоторое дублирование кода между двумя моделями, то вы можете использовать (или несколько) микшин (ов) для совместного использования кода между ними.

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

Я использую наследование, только если существует реальная is_a связь, а не shares_some_code_with отношение между классами to. И что более важно: я использую его тогда и только тогда, когда у него есть техническое преимущество для меня. В противном случае есть гораздо лучшие способы совместного использования кода между классами в ruby.