Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much, much, much less code.
You would use either plugin / gem if you wished that when you called destroy on an Active Record object that it didn't actually destroy it, but just hide the record. Paranoia does this by setting a deleted_at field to the current time when you destroy a record, and hides it by scoping all queries on your model to only include records which do not have a deleted_at field.
If you wish to actually destroy an object you may call really_destroy!. WARNING: This will also really destroy all dependent: destroy records, so please aim this method away from face when using.**
If a record has has_many associations defined AND those associations have dependent: :destroy set on them, then they will also be soft-deleted if acts_as_paranoid is set, otherwise the normal destroy will be called.
For Rails 3, please use version 1 of Paranoia:
gem "paranoia", "~> 1.0"For Rails 4, please use version 2 of Paranoia:
gem "paranoia", "~> 2.0"Of course you can install this from GitHub as well:
gem "paranoia", :github => "radar/paranoia", :branch => "master"
# or
gem "paranoia", :github => "radar/paranoia", :branch => "rails4"Then run:
bundle installUpdating is as simple as bundle update paranoia.
Run:
rails generate migration AddDeletedAtToClients deleted_at:datetime:indexand now you have a migration
class AddDeletedAtToClients < ActiveRecord::Migration
def change
add_column :clients, :deleted_at, :datetime
add_index :clients, :deleted_at
end
endclass Client < ActiveRecord::Base
acts_as_paranoid
# ...
endHey presto, it's there! Calling destroy will now set the deleted_at column:
>> client.deleted_at
# => nil
>> client.destroy
# => client
>> client.deleted_at
# => [current timestamp]If you really want it gone gone, call really_destroy!:
>> client.deleted_at
# => nil
>> client.really_destroy!
# => clientIf you want a method to be called on destroy, simply provide a before_destroy callback:
class Client < ActiveRecord::Base
acts_as_paranoid
before_destroy :some_method
def some_method
# do stuff
end
# ...
endIf you want to use a column other than deleted_at, you can pass it as an option:
class Client < ActiveRecord::Base
acts_as_paranoid column: :destroyed_at
...
endIf you want to access soft-deleted associations, override the getter method:
def product
Product.unscoped { super }
endIf you want to find all records, even those which are deleted:
Client.with_deletedIf you want to find only the deleted records:
Client.only_deletedIf you want to check if a record is soft-deleted:
client.destroyed?If you want to restore a record:
Client.restore(id)If you want to restore a whole bunch of records:
Client.restore([id1, id2, ..., idN])If you want to restore a record and their dependently destroyed associated records:
Client.restore(id, :recursive => true)If you want callbacks to trigger before a restore:
before_restore :callback_name_goes_hereFor more information, please look at the tests.
You can replace the older acts_as_paranoid methods as follows:
| Old Syntax | New Syntax |
|---|---|
find_with_deleted(:all) |
Client.with_deleted |
find_with_deleted(:first) |
Client.with_deleted.first |
find_with_deleted(id) |
Client.with_deleted.find(id) |
The recover method in acts_as_paranoid runs update callbacks. Paranoia's
restore method does not do this.
Most databases ignore null columns when it comes to resolving unique index
constraints. This means unique constraints that involve nullable columns may be
problematic. Instead of using NULL to represent a not-deleted row, you can pick
a value that you want paranoia to mean not deleted. Note that you can/should
now apply a NOT NULL constraint to your deleted_at column.
Per model:
# pick some value
acts_as_paranoid sentinel_value: DateTime.new(0)or globally in a rails initializer, e.g. config/initializer/paranoia.rb
Paranoia.default_sentinel_value = DateTime.new(0)This gem is released under the MIT license.