Пользователь
0,0
рейтинг
29 декабря 2009 в 15:38

Разработка → STI — одна таблица и много моделей

Вчера, в заметке про полиморфные связи в комментариях был упомянут паттерн STI. Как выяснилось, не все знают что это такое, как работает и зачем нужно. Решил восполнить этот информационный пробел и вкратце рассказать об этом шаблоне проектирования и его реализации в Рельсе.

STI (Single Table Inheritance) — паттерн проектирования, который позволяет перенести объектно-ориентированное наследование на таблицу реляционной базы данных. В таблице БД должно присутствовать поле идентифицирующее название класса в иерархии. Зачастую, в том числе в RoR, поле называют type.

Таким образом, мы можем иметь одну таблицу и несколько типов объектов (моделей), которые будут в ней храниться. В случае с вышеупомянутой хабразаметкой — это одна таблица постов, которая хранит посты разных типов: ссылка, подкаст, статья, перевод и т.д.

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

Приступим.

Определяемся с задачей


Допустим, в нашем приложении (например интернет-магазине) нам требуется реализовать иерархию пользователей с различными полномочиями и, возможно, дополнительной логикой. Пусть это будут: администратор, менеджер и рядовой пользователь. Вполне логично для каждого создать отдельную модель: Administrator, Manager, User. Учетные записи всех пользователей хранятся в одной таблице базы данных.

Создаем структуру БД


Нам требуется одна таблица, в целях максимального упрощения в ней будут два поля: username и password. Также, нам нужно как-то хранить тип пользователя, по умолчанию в Рельсе для этих целей используется поле под названием type.

В итоге получаем следующую структуру:
CREATE TABLE users (<br> id INT NOT NULL AUTO_INCREMENT,<br> username VARCHAR(20) NOT NULL UNIQUE,<br> password VARCHAR(32) NOT NULL,<br> type VARCHAR(40) NOT NULL,<br> PRIMARY KEY (id)<br>);

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

Создаем модели


Создаем модель рядового пользователя:
class User < ActiveRecord::Base<br>end

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

Создаем модель менеджера, наследуемся от базового пользователя:
class Manager < User<br>end

Создаем модель администратора, наследуемся от менеджера:
class Administrator < Manager<br>end

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

Используем!


Теперь в контроллере мы можем делать выборки из моделей привычным способом:
users = User.find(:all)
В данном случае мы получим всех пользователей, включая рядовых, менеджеров и администраторов.

Но если мы сделаем выборку из модели Administrator, то получим только администраторов:
administrators = Administrator.find(:all)

Вместо заключения


В данной заметке мы пропустили многие аспекты, которые не имеют прямого отношения к основной теме от написания миграций до использования генераторов. Также упомянуты далеко не все возможности, которые предоставляет Рельсовый ActiveRecord при использовании STI. Интересующиеся могут изучить эти моменты самостоятельно.

Single Table Inheritance у Мартина Фаулера
Документация по ActiveRecord в Ruby on Rails
veevtam @veevtam
карма
5,7
рейтинг 0,0
Реклама помогает поддерживать и развивать наши сервисы

Подробнее
Спецпроект

Самое читаемое Разработка

Комментарии (8)

  • +3
    Для полноты картины было бы здорово привести пример заполнения таблицы данными и результаты выборок.
  • +2
    Хе, моя статья сподвигла написать уже 2 статьи в блог Ruby on Rails. Это ли не повод радоваться?!
    Спасибо за интересный материал
    • 0
      Вам спасибо за положенное начало :) Будем надеяться: эти две статьи не последние.
  • +1
    Subaru Tecnica International!
  • 0
    Можно указать ещё такой момент:
    так как таблица одна, а моделей несколько то для всех атрибутов будут созданы соответствующие поля в таблице.
    В указанном примере никаких дополнительных атрибутов в моделях нету поэтому их нет и в таблице, если же у администраторов и менеджеров будут какие то свои непересекающиеся атрибуты, то понадобится заводить эти поля в таблице.
    STI позволяет как видно из примеров элегантно обойтись одной таблицей для схожих моделей,
    а в чём подводные камни?
  • 0
    • 0
      За ссылку спасибо :)

      Только я все из своей головы писал, с «оригиналом» не знаком, а если бы переводил — оформил бы как перевод.
  • 0
    Спасибо за наводку. Весь день мучился над поиском решения.

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