Наследование в одной таблице для ссылки на дочерний класс с собственными полями - PullRequest
2 голосов
/ 04 мая 2011

Я использую 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 (или * 1005)* запись) в таблице User, в которой выполняется следующая

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

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

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

1 Ответ

7 голосов
/ 04 мая 2011

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

Как правило, «путь Rails» состоит в том, чтобы объединить все возможные поля, которые требуются, в одну таблицу и использовать 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 и common_profile_id, где таблицы admin_profiles и common_profiles содержат необходимые дополнительные поля.

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

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

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

...