RoR: STI / MTI / Mixin путаница - PullRequest
       20

RoR: STI / MTI / Mixin путаница

2 голосов
/ 18 марта 2011

У меня есть проблема, которая, я считаю, является основной для большинства разработчиков RoR.На самом деле, речь идет скорее о «понимании», чем о его программировании (я уже программировал несколько модулей, чтобы иметь возможность расширить ActiveRecord :: Base, чтобы можно было легко создавать связанные с Ext-JS вещи без каких-либо проблем).

Давайте рассмотрим простой пример, я буду говорить на ORM-ориентированном языке, а не на языке базы данных / модели.

  • ThirdParty - это базовая сущность, имеющая общий член с именем «label».
  • Экземпляр ThirdParty может быть Клиентом, Поставщиком, обоими или ни одним из них (так что Клиент / Поставщик похожи на конкретные интерфейсы, а не на унаследованные классы).
  • Как Заказчик, так и Поставщик имеют специализированных членов, которые для большинства из них уникальны для каждого соответствующего класса (Клиент / Поставщик не разделяют много данных, кроме поля метки, с которым они связаны через ThirdParty).

Я пытался делать разные вещи:

  • ThirdParty
  • Клиент
  • Поставщик

[редактировать] пропустил мое объяснение здесь.я имел в виду: один экземпляр ThirdParty может быть клиентом, поставщиком, ОБА ИЛИ НЕТ.Как отметил первый комментатор, мой пример может быть не лучшим ... Вы можете заменить «ThirdParty» на «Character», а «Customer» / «Supplier» на «Archer» / «SwordsMan».Персонаж может быть один, два, оба или ни одного, но предоставит информацию о любом экземпляре Персонажа.Методы get в Archer / SwordsMan должны возвращать экземпляры Character, «реализующие» контракт интерфейса, а не просто возвращать их экземпляр с помощью «getter» для объекта персонажа.[/ EDIT]

Также я попробовал:

  • ThirdParty
  • Customer
  • Поставщик

Но мне это кажется немного "уродливым", потому что я должен сделать Customer.find (что-то).third_party.label для доступа к данным, «унаследованным» моими «интерфейсами».

Кроме того, я мог бы включить поле customer_id и supplier_id в мою модель ThirdParty, но это тоже не кажется правильным, потому что одна ThirdPartyможет быть и то, и другое, или ни одного из них ...

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

Я также много читал на эту тему, как в таком блоге: http://mediumexposure.com/multiple-table-inheritance-active-record/ ... но я потерялся в правильном способе сделать это (В большинстве документов, которые я нашел по этому вопросу, неясно, относится ли это к Rails 1, 2, 3 ... Что недавно было реализовано по этому вопросу и т. Д.).

Может кто-нибудь предоставить мне различные"современные" веб-сайты или пример, соответствующий приведенному мною примеру?

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

PS: Если вам нужно, чтобы я объяснил больше, что я ищу, я могу попробовать ... Но имейте в виду, что мой английский немного "ограничен" в этой области, так как ям относительно новый для RoR.

Ответы [ 2 ]

3 голосов
/ 19 марта 2011

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

module ThirdParty
  def self.included(base)
    base.extend ClassMethods
  end

  module ClassMethods
    # define your shared class methods here
  end

  # define you shared instance methods down here
end

class Customer < ActiveRecord::Base
  include ThirdParty
end

class Supplier < ActiveRecord::Base
  include ThirdParty
end

Это позволяет вам определять методы, которые используют атрибут label каждого включающего класса. Вы упоминаете, что хотели бы иметь возможность взаимодействовать с другими моделями, возможно, полиморфно. Если эти ассоциации присутствуют во всех объектах ThirdParty, вы просто устанавливаете ассоциации в вызове self.included (используя instance_eval) или в ClassMethods в качестве метода:

module ThirdParty
  def self.included(base)
    base.extend ClassMethods
    base.instance_eval do
      has_many :buyers, :as => :third_party
    end
  end

  module ClassMethods
    def has_address
      has_one :address, :as => :third_party
      delegate :street, :city, :state, :zip, :to => :address
    end
  end
end

class Supplier < ActiveRecord::Base
  include ThirdParty # this would set up the :buyers association

  has_address # this sets up the address association
end

Надеюсь, это поможет. Для получения более подробной информации о таких вещах, как это просто Google "ruby mixin" - там тонна информации.

1 голос
/ 29 апреля 2011

Недавно я разработал многообещающий проект для реализации множественного наследования таблиц и классов в Rails. Я провел несколько дней, подвергая его быстрой разработке, исправлениям, комментированию и документированию, и переиздал его как CITIER (Внедрение классов и наследование таблиц для Rails).

Я думаю, вы могли бы объединить это с ответами выше?

Рассмотрите возможность взглянуть на это: http://peterhamilton.github.com/citier

По сути, вы можете иметь общие поля в своем классе ThirdParty и создать объект Customer или Supplier, который их наследует.

Вы могли бы создать модуль с функциями, используемыми в них обоих, и поделиться им между ними?

CITIER не позволит вам иметь третье лицо в качестве Клиента и Поставщика одновременно, так как оно полагается на наследование Ruby, которое не поддерживает множественное наследование. Я полагаю, что какое-то совместное модульное решение заставит эту часть работать?

На самом деле, CITIER уже использует что-то похожее на ответ выше, поэтому будет видеть правильный путь.

...