Commit 7098750c by Ryan Bigg

Merge pull request #221 from duderman/real_destroy_callback

real_destroy callback
parents 857ed343 b468111d
...@@ -94,22 +94,6 @@ If you really want it gone *gone*, call `really_destroy!`: ...@@ -94,22 +94,6 @@ If you really want it gone *gone*, call `really_destroy!`:
# => client # => client
``` ```
If you want a method to be called on destroy, simply provide a `before_destroy` callback:
``` ruby
class Client < ActiveRecord::Base
acts_as_paranoid
before_destroy :some_method
def some_method
# do stuff
end
# ...
end
```
If you want to use a column other than `deleted_at`, you can pass it as an option: If you want to use a column other than `deleted_at`, you can pass it as an option:
``` ruby ``` ruby
...@@ -180,12 +164,6 @@ Client.restore(id, :recursive => true) ...@@ -180,12 +164,6 @@ Client.restore(id, :recursive => true)
client.restore(:recursive => true) client.restore(:recursive => true)
``` ```
If you want callbacks to trigger before a restore:
``` ruby
before_restore :callback_name_goes_here
```
For more information, please look at the tests. For more information, please look at the tests.
#### About indexes: #### About indexes:
...@@ -221,6 +199,24 @@ You can replace the older `acts_as_paranoid` methods as follows: ...@@ -221,6 +199,24 @@ You can replace the older `acts_as_paranoid` methods as follows:
The `recover` method in `acts_as_paranoid` runs `update` callbacks. Paranoia's The `recover` method in `acts_as_paranoid` runs `update` callbacks. Paranoia's
`restore` method does not do this. `restore` method does not do this.
## Callbacks
Paranoia provides few callbacks. It triggers `destroy` callback when the record is marked as deleted and `real_destroy` when the record is completely removed from database. It also calls `restore` callback when record is restored via paranoia
For example if you want to index you records in some search engine you can do like this:
```ruby
class Product < ActiveRecord::Base
acts_as_paranoid
after_destroy :update_document_in_search_engine
after_restore :update_document_in_search_engine
after_real_destroy :remove_document_from_search_engine
end
```
You can use these events just like regular Rails callbacks with before, after and around hooks.
## License ## License
This gem is released under the MIT license. This gem is released under the MIT license.
...@@ -47,18 +47,20 @@ module Paranoia ...@@ -47,18 +47,20 @@ module Paranoia
module Callbacks module Callbacks
def self.extended(klazz) def self.extended(klazz)
klazz.define_callbacks :restore [:restore, :real_destroy].each do |callback_name|
klazz.define_callbacks callback_name
klazz.define_singleton_method("before_restore") do |*args, &block| klazz.define_singleton_method("before_#{callback_name}") do |*args, &block|
set_callback(:restore, :before, *args, &block) set_callback(callback_name, :before, *args, &block)
end end
klazz.define_singleton_method("around_restore") do |*args, &block| klazz.define_singleton_method("around_#{callback_name}") do |*args, &block|
set_callback(:restore, :around, *args, &block) set_callback(callback_name, :around, *args, &block)
end end
klazz.define_singleton_method("after_restore") do |*args, &block| klazz.define_singleton_method("after_#{callback_name}") do |*args, &block|
set_callback(:restore, :after, *args, &block) set_callback(callback_name, :after, *args, &block)
end
end end
end end
end end
...@@ -172,25 +174,29 @@ class ActiveRecord::Base ...@@ -172,25 +174,29 @@ class ActiveRecord::Base
alias :destroy_without_paranoia :destroy alias :destroy_without_paranoia :destroy
def really_destroy! def really_destroy!
dependent_reflections = self.class.reflections.select do |name, reflection| transaction do
reflection.options[:dependent] == :destroy run_callbacks(:real_destroy) do
end dependent_reflections = self.class.reflections.select do |name, reflection|
if dependent_reflections.any? reflection.options[:dependent] == :destroy
dependent_reflections.each do |name, reflection| end
association_data = self.send(name) if dependent_reflections.any?
# has_one association can return nil dependent_reflections.each do |name, reflection|
# .paranoid? will work for both instances and classes association_data = self.send(name)
if association_data && association_data.paranoid? # has_one association can return nil
if reflection.collection? # .paranoid? will work for both instances and classes
association_data.with_deleted.each(&:really_destroy!) if association_data && association_data.paranoid?
else if reflection.collection?
association_data.really_destroy! association_data.with_deleted.each(&:really_destroy!)
else
association_data.really_destroy!
end
end
end end
end end
write_attribute(paranoia_column, current_time_from_proper_timezone)
destroy_without_paranoia
end end
end end
write_attribute(paranoia_column, current_time_from_proper_timezone)
destroy_without_paranoia
end end
include Paranoia include Paranoia
......
...@@ -453,6 +453,14 @@ class ParanoiaTest < test_framework ...@@ -453,6 +453,14 @@ class ParanoiaTest < test_framework
assert RelatedModel.unscoped.exists?(child_2.id) assert RelatedModel.unscoped.exists?(child_2.id)
end end
def test_really_destroy_behavior_for_callbacks
model = CallbackModel.new
model.save
model.really_destroy!
assert model.instance_variable_get(:@real_destroy_callback_called)
end
def test_really_delete def test_really_delete
model = ParanoidModel.new model = ParanoidModel.new
model.save model.save
...@@ -871,15 +879,16 @@ end ...@@ -871,15 +879,16 @@ end
class CallbackModel < ActiveRecord::Base class CallbackModel < ActiveRecord::Base
acts_as_paranoid acts_as_paranoid
before_destroy {|model| model.instance_variable_set :@destroy_callback_called, true } before_destroy { |model| model.instance_variable_set :@destroy_callback_called, true }
before_restore {|model| model.instance_variable_set :@restore_callback_called, true } before_restore { |model| model.instance_variable_set :@restore_callback_called, true }
before_update {|model| model.instance_variable_set :@update_callback_called, true } before_update { |model| model.instance_variable_set :@update_callback_called, true }
before_save {|model| model.instance_variable_set :@save_callback_called, true} before_save { |model| model.instance_variable_set :@save_callback_called, true}
before_real_destroy { |model| model.instance_variable_set :@real_destroy_callback_called, true }
after_destroy {|model| model.instance_variable_set :@after_destroy_callback_called, true } after_destroy { |model| model.instance_variable_set :@after_destroy_callback_called, true }
after_commit {|model| model.instance_variable_set :@after_commit_callback_called, true } after_commit { |model| model.instance_variable_set :@after_commit_callback_called, true }
validate {|model| model.instance_variable_set :@validate_called, true } validate { |model| model.instance_variable_set :@validate_called, true }
def remove_called_variables def remove_called_variables
instance_variables.each {|name| (name.to_s.end_with?('_called')) ? remove_instance_variable(name) : nil} instance_variables.each {|name| (name.to_s.end_with?('_called')) ? remove_instance_variable(name) : nil}
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment