Удаление записей с возможностью восстановления
Проблема
Довольно часто встречается ситуация, когда записи из таблиц должны удаляться не на совсем, а с возможностью восстановления.
Как издревле решался такой вопрос на каком нибудь ПХП? Известно как: добавлялась колонка-флаг deleted, и потом во всех SQL-запросах у нас появлялся дополнительный кондишн where deleted = 0.
Радости от этого, как известно, было мало.
Решение
На руби такой подход реализован в act_as_paranoid. Там переопределяются методы типа find, count и destroy, так что уже ручками естественно кондишены прописывать надобности нет и система начинает вести себя так, будто записей с установленной датой deleted_on нет.
Чтобы таки добраться до этих записей, определен метод find_with_deleted.
Все бы хорошо, но acts_as_paranoid периодически становился неработоспособным в зависимости от версии рельсов. Вот и сейчас, провозившись с ним некоторое время, я решил поискать альтернативные решения. И нашел.

Интересная альтернатива
Другой подход - вынести удаленные записи в отдельную таблицу и хранить их там до востребования.
Ну и действительно - удалили тебя, нечего лежать вместе с рабочими документами, дуй в мусорку - жди своей участи.
Этот вариант реализован в плагине acts_as_restorable, который гораздо менее популярен набившего оскомину параноида.
Работает он так:
- Переопределяет метод
destroyтак, что перед удалением записи складываются в таблицу deleted_records. Данные объекта при этом сериализуются в XML и записываются текстом в отдельное поле. - Причем в эту же таблицу складываются все подчиненные через
has_many :dependents, :dependent => :destroyзаписи любой вложенности. - С удаленными записями мы можем работать как с обычными моделями и организовать например для них REST-контроллер с листингом удаленных объектов и возможностью восстановления
Все бы хорошо, но при попытке его использовать
- выяснилось что, хотя записи и складываются до любого уровня вложенности, разворачиваться обратно они совершенно не хотят, т.е. восстановить данные получается не глубже одного has_many
- нашлась пара багов с неправильным именованием методов при десериализации, которые мешали нормально работе плагина
- стало ясно, что в случаях c
has_many :my_articles, :class_name => 'Article'оно работать не будет
Работа над ошибками
Начал я потихоньку это все исправлять, а получилось в итоге, что значительно переписал этот плагин.
Кому интересно, взять можно отсюда:
svn co http://acts-as-nested-restorable.googlecode.com/svn/trunk/ acts_as_nested_restorable
Все пока достаточно сыро - нет ни описания, ни тестов, но вполне себе работает - в моем проекте успешно складывается и разматывается has_many-цепочка customers -> invoices -> invoice_lines
Насчет описания и тестов, надеюсь в ближайшие дни исправиться.
Комментариев: 2
Написать! | RSS | Trackback uri