Удаление записей с возможностью восстановления

Проблема

Довольно часто встречается ситуация, когда записи из таблиц должны удаляться не на совсем, а с возможностью восстановления.
Как издревле решался такой вопрос на каком нибудь ПХП? Известно как: добавлялась колонка-флаг deleted, и потом во всех SQL-запросах у нас появлялся дополнительный кондишн where deleted = 0.
Радости от этого, как известно, было мало.

Решение

На руби такой подход реализован в act_as_paranoid. Там переопределяются методы типа find, count и destroy, так что уже ручками естественно кондишены прописывать надобности нет и система начинает вести себя так, будто записей с установленной датой deleted_on нет.
Чтобы таки добраться до этих записей, определен метод find_with_deleted.

Все бы хорошо, но acts_as_paranoid периодически становился неработоспособным в зависимости от версии рельсов. Вот и сейчас, провозившись с ним некоторое время, я решил поискать альтернативные решения. И нашел.

acts_as_nested_restorable rails plugin

Интересная альтернатива

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

Этот вариант реализован в плагине 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

Насчет описания и тестов, надеюсь в ближайшие дни исправиться.


Дополнительная информация