Paranoia got you down?
Acts as recoverable is a plugin for active record that provides a great way to restore objects that have been deleted. It’s similar in function to acts_as_paranoid, but puts a much smaller strain on the the developer (i.e. you) - especially with associations - and works correctly in a number of cases where acts_as_paranoid either doesn’t work or requires a whole lot of hacking. The plugin is designed to work in cases where you want to rescue the user from accidental deletion or allow them to recover deleted data in the future. And in order to make it work, you need exactly one line of code. The plugin works by serializing the deleted objects’ attributes, including associated objects, into a table. Objects stored in that table can be queried and recovered through a call that returns a copy of the original deleted object.
PROBLEMS, QUESTIONS, TODOS:
1) No API for recovering objects.
Install the plugin:
./script/plugin install [email protected]:aub/acts_as_recoverable.git
The plugin requires a table where it can store the data for deleted models. The table can be created easily enough:
./script/generate recoverable_objects_migration rake db:migrate
All set. The schema for the generated table is:
create_table :recoverable_objects, :force => true do |t| t.text :object_hash t.timestamps end
class Article < ActiveRecord::Base acts_as_recoverable end
That was easy.
@article.destroy
Hey, that looks familiar. Calling destroy! on the object will do a normal destroy and skip the recoverable process.
This I need to work on. At present, you would have to search for things in the RecoverableObjects table, and there is no great way to do so. Once you have that object, though:
# will return an unsaved copy of the original object recoverable_object.recover # will return a saved copy of the original object and remove it from the # recoverable_objects table. recoverable_object.recover!
Associations? No problem. When a recoverable object is destroyed, data in :dependent => :destroy and has_and_belongs_to_many associations will be saved and recovered along with it. This works recursively, and objects in the associations are not required to be marked as recoverable in order to be saved.
class Article < ActiveRecord::Base acts_as_recoverable has_many :comments, :dependent => :destroy end class Comment < ActiveRecord::Base belongs_to :article end a = Article.create(:comments => { Comment.create, Comment.create }) a.destroy # This line intentionally left blank a = recoverable_object.recover a.comments.size # => 2
Note that the Comment model does not itself have to be recoverable in order for this to work. With has_and_belongs_to_many, the ids of the associated objects are stored even if the association does not have :dependent => :destroy. Example:
class Listing < ActiveRecord::Base has_and_belongs_to_many :locations end class Location < ActiveRecord::Base has_and_belongs_to_many :listings end l = Listing.create(:locations => { Location.create, Location.create }) l.destroy # Again intentionally left blank l = recoverable_object.recover l.locations.size # => 2
Spiffy!
Copyright © 2008 Aubrey Holland, patch, released under the MIT license