Module: IsParanoid::ClassMethods
- Defined in:
- lib/is_paranoid.rb
Instance Method Summary collapse
-
#delete_all(conditions = nil) ⇒ Object
Actually delete the model, bypassing the safety net.
-
#method_missing(name, *args, &block) ⇒ Object
find_with_destroyed and other blah_with_destroyed and blah_destroyed_only methods are defined here.
-
#restore(id, options = {}) ⇒ Object
Use update_all with an exclusive scope to restore undo the soft-delete.
-
#with_exclusive_scope(method_scoping = {}, &block) ⇒ Object
with_exclusive_scope is used internally by ActiveRecord when preloading associations.
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(name, *args, &block) ⇒ Object
find_with_destroyed and other blah_with_destroyed and blah_destroyed_only methods are defined here
89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 |
# File 'lib/is_paranoid.rb', line 89 def method_missing name, *args, &block if name.to_s =~ /^(.*)(_destroyed_only|_with_destroyed)$/ and self.respond_to?($1) self.extend(Module.new{ if $2 == '_with_destroyed' # Example: # def count_with_destroyed(*args) # self.with_exclusive_scope{ self.send(:count, *args) } # end define_method name do |*args| self.with_exclusive_scope{ self.send($1, *args) } end else # Example: # def count_destroyed_only(*args) # self.with_exclusive_scope do # with_scope({:find => { :conditions => ["#{destroyed_field} IS NOT ?", nil] }}) do # self.send(:count, *args) # end # end # end define_method name do |*args| self.with_exclusive_scope do with_scope({:find => { :conditions => ["#{self.table_name}.#{destroyed_field} IS NOT ?", field_not_destroyed] }}) do self.send($1, *args, &block) end end end end }) self.send(name, *args, &block) else super(name, *args, &block) end end |
Instance Method Details
#delete_all(conditions = nil) ⇒ Object
Actually delete the model, bypassing the safety net. Because this method is called internally by Model.delete(id) and on the delete method in each instance, we don’t need to specify those methods separately
34 35 36 |
# File 'lib/is_paranoid.rb', line 34 def delete_all conditions = nil self.with_exclusive_scope { super conditions } end |
#restore(id, options = {}) ⇒ Object
Use update_all with an exclusive scope to restore undo the soft-delete. This bypasses update-related callbacks.
By default, restores cascade through associations that are belongs_to :dependent => :destroy and under is_paranoid. You can prevent restoration of associated models by passing :include_destroyed_dependents => false, for example:
Android.restore(:include_destroyed_dependents => false)
Alternatively you can specify which relationships to restore via :include, for example:
Android.restore(:include => [:parts, memories])
Please note that specifying :include means you’re not using :include_destroyed_dependents by default, though you can explicitly use both if you want all has_* relationships and specific belongs_to relationships, for example
Android.restore(:include => [:home, :planet], :include_destroyed_dependents => true)
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/is_paranoid.rb', line 59 def restore(id, = {}) .reverse_merge!({:include_destroyed_dependents => true}) unless [:include] with_exclusive_scope do update_all( "#{destroyed_field} = #{connection.quote(field_not_destroyed)}", primary_key.to_sym => id ) end self.reflect_on_all_associations.each do |association| if association.[:dependent] == :destroy and association.klass.respond_to?(:restore) dependent_relationship = association.macro.to_s =~ /^has/ if should_restore?(association.name, dependent_relationship, ) if dependent_relationship (association.klass, association.primary_key_name, id, ) else ( association.klass, association.klass.primary_key, self.first(id).send(association.primary_key_name), ) end end end end end |
#with_exclusive_scope(method_scoping = {}, &block) ⇒ Object
with_exclusive_scope is used internally by ActiveRecord when preloading associations. Unfortunately this is problematic for is_paranoid since we want preloaded is_paranoid items to still be scoped to their deleted conditions. so we override that here.
130 131 132 133 134 135 136 137 138 |
# File 'lib/is_paranoid.rb', line 130 def with_exclusive_scope(method_scoping = {}, &block) # this is rather hacky, suggestions for improvements appreciated... the idea # is that when the caller includes the method preload_associations, we want # to apply our is_paranoid conditions if caller.any?{|c| c =~ /\d+:in `preload_associations'$/} method_scoping.deep_merge!(:find => {:conditions => {destroyed_field => field_not_destroyed} }) end super method_scoping, &block end |