Вы можете попробовать что-нибудь в следующем духе.
class Account < ActiveRecord::Base
belongs_to :corp_or_gov_customer, :polymorphic => true
def account_id
self.id
end
end
class GovernmentCustomer < ActiveRecord::Base
has_one :account, :as => :corp_or_gov_customer, :dependent => :destroy
def method_missing( symbol, *args )
self.account.send( symbol, *args )
end
end
class CorporateCustomer < ActiveRecord::Base
has_one :account, :as => :corp_or_gov_customer, :dependent => :destroy
belongs_to :priv_or_pub_customer, :polymorphic => true
def method_missing( symbol, *args )
self.account.send( symbol, *args )
end
end
class PrivateCustomer < ActiveRecord::Base
has_one :corporate_customer, :as => :priv_or_pub_customer, :dependent => :destroy
def method_missing( symbol, *args )
self.corporate_customer.send( symbol, *args )
end
end
class PublicCustomer < ActiveRecord::Base
has_one :corporate_customer, :as => :priv_or_pub_customer, :dependent => :destroy
def method_missing( symbol, *args )
self.corporate_customer.send( symbol, *args )
end
end
Я не проверял этот код (и даже не проверял его на синтаксис). Скорее, он предназначен просто для того, чтобы указать вам направление полиморфных отношений.
Переопределение method_missing для вызова вложенных объектов сохраняет код написания как
my_public_customer.corporate_customer.account.some_attribute
вместо этого вы можете просто написать
my_public_customer.some_attribute
В ответ на комментарий:
Проблема в том, что такие понятия, как «есть», «имеет много» и «принадлежит», все реализуются отношениями внешних ключей в реляционной модели. Понятие наследования совершенно чуждо системам RDB. Семантика этих отношений должна быть отображена на реляционную модель выбранной вами технологией ORM.
Но библиотека ActiveRecord в Rails не реализует "is_a" как отношение между моделями.
Есть несколько способов смоделировать иерархию классов в RDB.
Единая таблица для всех учетных записей, но с избыточными атрибутами - это поддерживается ActiveRecord, просто добавляя столбец типа в вашу таблицу. а затем создайте иерархию классов следующим образом:
class Account < ActiveRecord::Base
class GovernmentCustomer < Account
class CorporateCustomer < Account
class PublicCustomer < CorporateCustomer
class PrivateCustomer < CorporateCustomer
Тогда, если вы вызовете PrivateCustomer.new, поле типа будет автоматически установлено на «PrivateCustomer», а при вызове Account.find возвращаемые объекты будут иметь правильный класс.
Я бы порекомендовал этот подход, потому что это самый простой способ делать то, что вы хотите.
Одна таблица для каждого конкретного класса - Насколько я знаю, для этого в ActiveRecord не предусмотрено сопоставление. Основная проблема этого метода заключается в том, что для получения списка всех учетных записей необходимо объединить три таблицы. Необходим какой-то главный индекс, который ведет к следующей модели.
Одна таблица для каждого класса - Вы можете думать о таблицах, которые представляют абстрактные классы, как некий единый индекс или каталог объектов, которые хранятся в таблицах для конкретных классов. Думая об этом таким образом, вы меняете отношение is_a на отношение has_a, например, объект имеет_a index_entry и index_entry принадлежит_ к объекту. Это может быть сопоставлено ActiveRecord с использованием полиморфных отношений.
В книге очень хорошо обсуждается эта проблема "Гибкая веб-разработка с Rails" (начиная со страницы 341 во втором издании)