Наследование одной таблицы для ссылки на дочерний класс с его собственными полями

#ruby-on-rails #ruby #ruby-on-rails-3 #class #single-table-inheritance

#ruby-on-rails #ruby #ruby-on-rails-3 #класс #наследование одной таблицы

Вопрос:

Я использую Ruby on Rails 3 и реализовал рабочее наследование одной таблицы следующим образом:

 class User < ActiveRecord::Base

  # Schema Information
  #
  # Table name: User
  #
  # id              : integer
  # type            : string
  # children_user_id: integer

  ...
end

class UserAdmin < User

  # Schema Information
  #
  # Table name: UserAdmin
  #
  # id             : integer
  # special_field1 : string
  # special_field2 : string
  # ...

  ...
end

class UserCommon < User

  # Schema Information
  #
  # Table name: UserCommon
  #
  # id             : integer
  # another_field1 : string
  # another_field2 : string
  # ...

  ...
end
  

Я хотел бы знать, выполняется ли при создании UserAdmin записи (или UserCommon записи) в User таблице следующее

 UserAdmin.create(:children_user_id => "1")
# or UserCommon.create(:children_user_id => "1")
  

можно каким-то образом «автоматически» создать (возможно, «Rails Way«!) новую запись также в UserAdmin таблице (или UserCommon table), которая имеет свои собственные поля (на уровне базы данных эти поля являются столбцами). Я хотел бы сделать это для того, чтобы «лучше обрабатывать» UserAdmin , потому что этот класс имеет другие атрибуты UserCommon класса.

Если это возможно, как я могу это сделать (возможно, используя инструкции модели ассоциации, обратные вызовы, полиморфизм, …)? У вас есть какие-нибудь советы по этому вопросу?

Ответ №1:

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

Обычно «Rails Way» заключается в объединении всех возможных полей, которые требуются, в одну таблицу и использовании STI для решения проблем сопоставления данных и проверки для вас. Однако существуют ограничения на то, что оно может скрывать от приложения, поскольку обычно определение поля означает, что оно может использоваться любым из классов, привязанных к этой таблице. Большинство людей не считают это проблемой.

Что вы, вероятно, хотите сделать, так это создать запись, к которой присоединяются в зависимости от типа пользователя, например:

 class User < ActiveRecord::Base
end

class AdminUser < User
  belongs_to :admin_profile
end

class CommonUser < User
  belongs_to :common_profile
end
  

Для этого потребовалась бы users таблица, имеющая столбец admin_profile_id and common_profile_id , в котором таблицы admin_profiles и common_profiles содержат требуемые дополнительные поля.

Атрибуты в этих таблицах могут быть сопоставлены обратно в базовый класс с помощью delegate метода по мере необходимости.

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

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

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

1. Возможно, вы что-то забыли после этой фразы: «Атрибуты в этих таблицах могут быть сопоставлены обратно в базовый класс с помощью». В любом случае, спасибо.

2. Вы правы. Я имел в виду «может быть отображен обратно в базовый класс с помощью delegate метода»