paranoia-2.1.3/0000755000175600017570000000000012627002214012344 5ustar pravipraviparanoia-2.1.3/LICENSE0000644000175600017570000000162512627002214013355 0ustar pravipraviPermission is hereby granted, without written agreement and without license or royalty fees, to use, copy, modify, and distribute this software and its documentation for any purpose, provided that the above copyright notice and the following two paragraphs appear in all copies of this software. IN NO EVENT SHALL THE COPYRIGHT HOLDER BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF THE COPYRIGHT HOLDER HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. THE COPYRIGHT HOLDER SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND THE COPYRIGHT HOLDER HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS. paranoia-2.1.3/.travis.yml0000644000175600017570000000021212627002214014450 0ustar pravipravilanguage: ruby rvm: - 2.0.0 - 2.1.0 - 2.2.0 - jruby-19mode env: - RAILS='~> 4.0.13' - RAILS='~> 4.1.10' - RAILS='~> 4.2.1' paranoia-2.1.3/README.md0000644000175600017570000001176612627002214013636 0ustar pravipravi# Paranoia Paranoia is a re-implementation of [acts\_as\_paranoid](http://github.com/technoweenie/acts_as_paranoid) for Rails 3 and Rails 4, 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. ## Getting Started Video Setup and basic usage of the paranoia gem [GoRails #41](https://gorails.com/episodes/soft-delete-with-paranoia) ## Installation & Usage For Rails 3, please use version 1 of Paranoia: ``` ruby gem "paranoia", "~> 1.0" ``` For Rails 4, please use version 2 of Paranoia: ``` ruby gem "paranoia", "~> 2.0" ``` Of course you can install this from GitHub as well: ``` ruby gem "paranoia", :github => "radar/paranoia", :branch => "rails3" # or gem "paranoia", :github => "radar/paranoia", :branch => "rails4" ``` Then run: ``` shell bundle install ``` Updating is as simple as `bundle update paranoia`. #### Run your migrations for the desired models Run: ``` shell rails generate migration AddDeletedAtToClients deleted_at:datetime:index ``` and now you have a migration ``` ruby class AddDeletedAtToClients < ActiveRecord::Migration def change add_column :clients, :deleted_at, :datetime add_index :clients, :deleted_at end end ``` ### Usage #### In your model: ``` ruby class Client < ActiveRecord::Base acts_as_paranoid # ... end ``` Hey presto, it's there! Calling `destroy` will now set the `deleted_at` column: ``` ruby >> client.deleted_at # => nil >> client.destroy # => client >> client.deleted_at # => [current timestamp] ``` If you really want it gone *gone*, call `really_destroy!`: ``` ruby >> client.deleted_at # => nil >> client.really_destroy! # => 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: ``` ruby class Client < ActiveRecord::Base acts_as_paranoid column: :destroyed_at ... end ``` If you want to access soft-deleted associations, override the getter method: ``` ruby def product Product.unscoped { super } end ``` If you want to include associated soft-deleted objects, you can (un)scope the association: ``` ruby class Person < ActiveRecord::Base belongs_to :group, -> { with_deleted } end Person.includes(:group).all ``` If you want to find all records, even those which are deleted: ``` ruby Client.with_deleted ``` If you want to find only the deleted records: ``` ruby Client.only_deleted ``` If you want to check if a record is soft-deleted: ``` ruby client.paranoia_destroyed? # or client.deleted? ``` If you want to restore a record: ``` ruby Client.restore(id) # or client.restore ``` If you want to restore a whole bunch of records: ``` ruby Client.restore([id1, id2, ..., idN]) ``` If you want to restore a record and their dependently destroyed associated records: ``` ruby Client.restore(id, :recursive => true) # or 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. #### About indexes: Beware that you should adapt all your indexes for them to work as fast as previously. For example, ``` ruby add_index :clients, :group_id add_index :clients, [:group_id, :other_id] ``` should be replaced with ``` ruby add_index :clients, :group_id, where: "deleted_at IS NULL" add_index :clients, [:group_id, :other_id], where: "deleted_at IS NULL" ``` Of course, this is not necessary for the indexes you always use in association with `with_deleted` or `only_deleted`. ## Acts As Paranoid Migration 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. ## License This gem is released under the MIT license. paranoia-2.1.3/test/0000755000175600017570000000000012627002214013323 5ustar pravipraviparanoia-2.1.3/test/paranoia_test.rb0000644000175600017570000010111612627002214016501 0ustar pravipravirequire 'active_record' ActiveRecord::Base.raise_in_transactional_callbacks = true if ActiveRecord::VERSION::STRING >= '4.2' require 'minitest/autorun' test_framework = defined?(MiniTest::Test) ? MiniTest::Test : MiniTest::Unit::TestCase require File.expand_path(File.dirname(__FILE__) + "/../lib/paranoia") def connect! ActiveRecord::Base.establish_connection :adapter => 'sqlite3', database: ':memory:' end def setup! connect! { 'parent_model_with_counter_cache_columns' => 'related_models_count INTEGER DEFAULT 0', 'parent_models' => 'deleted_at DATETIME', 'paranoid_models' => 'parent_model_id INTEGER, deleted_at DATETIME', 'paranoid_model_with_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER', 'paranoid_model_with_build_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_and_build_id INTEGER, name VARCHAR(32)', 'paranoid_model_with_anthor_class_name_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, paranoid_model_with_has_one_id INTEGER', 'paranoid_model_with_foreign_key_belongs' => 'parent_model_id INTEGER, deleted_at DATETIME, has_one_foreign_key_id INTEGER', 'not_paranoid_model_with_belongs' => 'parent_model_id INTEGER, paranoid_model_with_has_one_id INTEGER', 'paranoid_model_with_has_one_and_builds' => 'parent_model_id INTEGER, color VARCHAR(32), deleted_at DATETIME, has_one_foreign_key_id INTEGER', 'featureful_models' => 'deleted_at DATETIME, name VARCHAR(32)', 'plain_models' => 'deleted_at DATETIME', 'callback_models' => 'deleted_at DATETIME', 'fail_callback_models' => 'deleted_at DATETIME', 'related_models' => 'parent_model_id INTEGER, parent_model_with_counter_cache_column_id INTEGER, deleted_at DATETIME', 'asplode_models' => 'parent_model_id INTEGER, deleted_at DATETIME', 'employers' => 'deleted_at DATETIME', 'employees' => 'deleted_at DATETIME', 'jobs' => 'employer_id INTEGER NOT NULL, employee_id INTEGER NOT NULL, deleted_at DATETIME', 'custom_column_models' => 'destroyed_at DATETIME', 'custom_sentinel_models' => 'deleted_at DATETIME NOT NULL', 'non_paranoid_models' => 'parent_model_id INTEGER', 'polymorphic_models' => 'parent_id INTEGER, parent_type STRING, deleted_at DATETIME', 'namespaced_paranoid_has_ones' => 'deleted_at DATETIME, paranoid_belongs_tos_id INTEGER', 'namespaced_paranoid_belongs_tos' => 'deleted_at DATETIME, paranoid_has_one_id INTEGER', }.each do |table_name, columns_as_sql_string| ActiveRecord::Base.connection.execute "CREATE TABLE #{table_name} (id INTEGER NOT NULL PRIMARY KEY, #{columns_as_sql_string})" end end class WithDifferentConnection < ActiveRecord::Base establish_connection adapter: 'sqlite3', database: ':memory:' connection.execute 'CREATE TABLE with_different_connections (id INTEGER NOT NULL PRIMARY KEY, deleted_at DATETIME)' acts_as_paranoid end setup! class ParanoiaTest < test_framework def setup ActiveRecord::Base.connection.tables.each do |table| ActiveRecord::Base.connection.execute "DELETE FROM #{table}" end end def test_plain_model_class_is_not_paranoid assert_equal false, PlainModel.paranoid? end def test_paranoid_model_class_is_paranoid assert_equal true, ParanoidModel.paranoid? end def test_plain_models_are_not_paranoid assert_equal false, PlainModel.new.paranoid? end def test_paranoid_models_are_paranoid assert_equal true, ParanoidModel.new.paranoid? end def test_paranoid_models_to_param model = ParanoidModel.new model.save to_param = model.to_param model.destroy assert model.to_param assert_equal to_param, model.to_param end def test_destroy_behavior_for_plain_models model = PlainModel.new assert_equal 0, model.class.count model.save! assert_equal 1, model.class.count model.destroy assert_equal true, model.deleted_at.nil? assert_equal 0, model.class.count assert_equal 0, model.class.unscoped.count end # Anti-regression test for #81, which would've introduced a bug to break this test. def test_destroy_behavior_for_plain_models_callbacks model = CallbackModel.new model.save model.remove_called_variables # clear called callback flags model.destroy assert_equal nil, model.instance_variable_get(:@update_callback_called) assert_equal nil, model.instance_variable_get(:@save_callback_called) assert_equal nil, model.instance_variable_get(:@validate_called) assert model.instance_variable_get(:@destroy_callback_called) assert model.instance_variable_get(:@after_destroy_callback_called) assert model.instance_variable_get(:@after_commit_callback_called) end def test_delete_behavior_for_plain_models_callbacks model = CallbackModel.new model.save model.remove_called_variables # clear called callback flags model.delete assert_equal nil, model.instance_variable_get(:@update_callback_called) assert_equal nil, model.instance_variable_get(:@save_callback_called) assert_equal nil, model.instance_variable_get(:@validate_called) assert_equal nil, model.instance_variable_get(:@destroy_callback_called) assert_equal nil, model.instance_variable_get(:@after_destroy_callback_called) assert model.instance_variable_get(:@after_commit_callback_called) end def test_destroy_behavior_for_paranoid_models model = ParanoidModel.new assert_equal 0, model.class.count model.save! assert_equal 1, model.class.count model.destroy assert_equal false, model.deleted_at.nil? assert_equal 0, model.class.count assert_equal 1, model.class.unscoped.count end def test_update_columns_on_paranoia_destroyed record = ParentModel.create record.destroy assert record.update_columns deleted_at: Time.now end def test_scoping_behavior_for_paranoid_models parent1 = ParentModel.create parent2 = ParentModel.create p1 = ParanoidModel.create(:parent_model => parent1) p2 = ParanoidModel.create(:parent_model => parent2) p1.destroy p2.destroy assert_equal 0, parent1.paranoid_models.count assert_equal 1, parent1.paranoid_models.only_deleted.count assert_equal 1, parent1.paranoid_models.deleted.count p3 = ParanoidModel.create(:parent_model => parent1) assert_equal 2, parent1.paranoid_models.with_deleted.count assert_equal [p1,p3], parent1.paranoid_models.with_deleted end def test_destroy_behavior_for_custom_column_models model = CustomColumnModel.new assert_equal 0, model.class.count model.save! assert_nil model.destroyed_at assert_equal 1, model.class.count model.destroy assert_equal false, model.destroyed_at.nil? assert model.paranoia_destroyed? assert_equal 0, model.class.count assert_equal 1, model.class.unscoped.count assert_equal 1, model.class.only_deleted.count assert_equal 1, model.class.deleted.count end def test_default_sentinel_value assert_equal nil, ParanoidModel.paranoia_sentinel_value end def test_sentinel_value_for_custom_sentinel_models model = CustomSentinelModel.new assert_equal 0, model.class.count model.save! assert_equal DateTime.new(0), model.deleted_at assert_equal 1, model.class.count model.destroy assert DateTime.new(0) != model.deleted_at assert model.paranoia_destroyed? assert_equal 0, model.class.count assert_equal 1, model.class.unscoped.count assert_equal 1, model.class.only_deleted.count assert_equal 1, model.class.deleted.count model.restore assert_equal DateTime.new(0), model.deleted_at assert !model.destroyed? assert_equal 1, model.class.count assert_equal 1, model.class.unscoped.count assert_equal 0, model.class.only_deleted.count assert_equal 0, model.class.deleted.count end def test_destroy_behavior_for_featureful_paranoid_models model = get_featureful_model assert_equal 0, model.class.count model.save! assert_equal 1, model.class.count model.destroy assert_equal false, model.deleted_at.nil? assert_equal 0, model.class.count assert_equal 1, model.class.unscoped.count end def test_destroy_behavior_for_has_one_with_build_and_validation_error model = ParanoidModelWithHasOneAndBuild.create model.destroy end # Regression test for #24 def test_chaining_for_paranoid_models scope = FeaturefulModel.where(:name => "foo").only_deleted assert_equal "foo", scope.where_values_hash['name'] assert_equal 2, scope.where_values.count end def test_only_destroyed_scope_for_paranoid_models model = ParanoidModel.new model.save model.destroy model2 = ParanoidModel.new model2.save assert_equal model, ParanoidModel.only_deleted.last assert_equal false, ParanoidModel.only_deleted.include?(model2) end def test_default_scope_for_has_many_relationships parent = ParentModel.create assert_equal 0, parent.related_models.count child = parent.related_models.create assert_equal 1, parent.related_models.count child.destroy assert_equal false, child.deleted_at.nil? assert_equal 0, parent.related_models.count assert_equal 1, parent.related_models.unscoped.count end def test_default_scope_for_has_many_through_relationships employer = Employer.create employee = Employee.create assert_equal 0, employer.jobs.count assert_equal 0, employer.employees.count assert_equal 0, employee.jobs.count assert_equal 0, employee.employers.count job = Job.create :employer => employer, :employee => employee assert_equal 1, employer.jobs.count assert_equal 1, employer.employees.count assert_equal 1, employee.jobs.count assert_equal 1, employee.employers.count employee2 = Employee.create job2 = Job.create :employer => employer, :employee => employee2 employee2.destroy assert_equal 2, employer.jobs.count assert_equal 1, employer.employees.count job.destroy assert_equal 1, employer.jobs.count assert_equal 0, employer.employees.count assert_equal 0, employee.jobs.count assert_equal 0, employee.employers.count end def test_delete_behavior_for_callbacks model = CallbackModel.new model.save model.delete assert_equal nil, model.instance_variable_get(:@destroy_callback_called) end def test_destroy_behavior_for_callbacks model = CallbackModel.new model.save model.destroy assert model.instance_variable_get(:@destroy_callback_called) end def test_destroy_on_readonly_record # Just to demonstrate the AR behaviour model = NonParanoidModel.create! model.readonly! assert_raises ActiveRecord::ReadOnlyRecord do model.destroy end # Mirrors behaviour above model = ParanoidModel.create! model.readonly! assert_raises ActiveRecord::ReadOnlyRecord do model.destroy end end def test_destroy_on_really_destroyed_record model = ParanoidModel.create! model.really_destroy! assert model.really_destroyed? assert model.paranoia_destroyed? model.destroy assert model.really_destroyed? assert model.paranoia_destroyed? end def test_destroy_on_unsaved_record # Just to demonstrate the AR behaviour model = NonParanoidModel.new model.destroy! assert model.really_destroyed? model.destroy! assert model.really_destroyed? # Mirrors behaviour above model = ParanoidModel.new model.destroy! assert model.paranoia_destroyed? model.destroy! assert model.paranoia_destroyed? end def test_restore model = ParanoidModel.new model.save id = model.id model.destroy assert model.paranoia_destroyed? model = ParanoidModel.only_deleted.find(id) model.restore! model.reload assert_equal false, model.paranoia_destroyed? end def test_restore_on_object_return_self model = ParanoidModel.create model.destroy assert_equal model.class, model.restore.class end # Regression test for #92 def test_destroy_twice model = ParanoidModel.new model.save model.destroy model.destroy assert_equal 1, ParanoidModel.unscoped.where(id: model.id).count end # Regression test for #92 def test_destroy_bang_twice model = ParanoidModel.new model.save! model.destroy! model.destroy! assert_equal 1, ParanoidModel.unscoped.where(id: model.id).count end def test_destroy_return_value_on_success model = ParanoidModel.create return_value = model.destroy assert_equal(return_value, model) end def test_destroy_return_value_on_failure model = FailCallbackModel.create return_value = model.destroy assert_equal(return_value, false) end def test_restore_behavior_for_callbacks model = CallbackModel.new model.save id = model.id model.destroy assert model.paranoia_destroyed? model = CallbackModel.only_deleted.find(id) model.restore! model.reload assert model.instance_variable_get(:@restore_callback_called) end def test_really_destroy model = ParanoidModel.new model.save model.really_destroy! refute ParanoidModel.unscoped.exists?(model.id) end def test_real_destroy_dependent_destroy parent = ParentModel.create child1 = parent.very_related_models.create child2 = parent.non_paranoid_models.create child3 = parent.create_non_paranoid_model parent.really_destroy! refute RelatedModel.unscoped.exists?(child1.id) refute NonParanoidModel.unscoped.exists?(child2.id) refute NonParanoidModel.unscoped.exists?(child3.id) end def test_real_destroy_dependent_destroy_after_normal_destroy parent = ParentModel.create child = parent.very_related_models.create parent.destroy parent.really_destroy! refute RelatedModel.unscoped.exists?(child.id) end def test_real_destroy_dependent_destroy_after_normal_destroy_does_not_delete_other_children parent_1 = ParentModel.create child_1 = parent_1.very_related_models.create parent_2 = ParentModel.create child_2 = parent_2.very_related_models.create parent_1.destroy parent_1.really_destroy! assert RelatedModel.unscoped.exists?(child_2.id) end def test_really_delete model = ParanoidModel.new model.save model.really_delete refute ParanoidModel.unscoped.exists?(model.id) end def test_multiple_restore a = ParanoidModel.new a.save a_id = a.id a.destroy b = ParanoidModel.new b.save b_id = b.id b.destroy c = ParanoidModel.new c.save c_id = c.id c.destroy ParanoidModel.restore([a_id, c_id]) a.reload b.reload c.reload refute a.paranoia_destroyed? assert b.paranoia_destroyed? refute c.paranoia_destroyed? end def test_restore_with_associations parent = ParentModel.create first_child = parent.very_related_models.create second_child = parent.non_paranoid_models.create parent.destroy assert_equal false, parent.deleted_at.nil? assert_equal false, first_child.reload.deleted_at.nil? assert_equal true, second_child.destroyed? parent.restore! assert_equal true, parent.deleted_at.nil? assert_equal false, first_child.reload.deleted_at.nil? assert_equal true, second_child.destroyed? parent.destroy parent.restore(:recursive => true) assert_equal true, parent.deleted_at.nil? assert_equal true, first_child.reload.deleted_at.nil? assert_equal true, second_child.destroyed? parent.destroy ParentModel.restore(parent.id, :recursive => true) assert_equal true, parent.reload.deleted_at.nil? assert_equal true, first_child.reload.deleted_at.nil? assert_equal true, second_child.destroyed? end # regression tests for #118 def test_restore_with_has_one_association # setup and destroy test objects hasOne = ParanoidModelWithHasOne.create belongsTo = ParanoidModelWithBelong.create anthorClassName = ParanoidModelWithAnthorClassNameBelong.create foreignKey = ParanoidModelWithForeignKeyBelong.create notParanoidModel = NotParanoidModelWithBelong.create hasOne.paranoid_model_with_belong = belongsTo hasOne.class_name_belong = anthorClassName hasOne.paranoid_model_with_foreign_key_belong = foreignKey hasOne.not_paranoid_model_with_belong = notParanoidModel hasOne.save! hasOne.destroy assert_equal false, hasOne.deleted_at.nil? assert_equal false, belongsTo.deleted_at.nil? # Does it restore has_one associations? hasOne.restore(:recursive => true) hasOne.save! assert_equal true, hasOne.reload.deleted_at.nil? assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}" assert_equal true, notParanoidModel.destroyed? assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record" assert ParanoidModelWithAnthorClassNameBelong.with_deleted.reload.count != 0, "There should be an other record" assert ParanoidModelWithForeignKeyBelong.with_deleted.reload.count != 0, "There should be a foreign_key record" end def test_new_restore_with_has_one_association # setup and destroy test objects hasOne = ParanoidModelWithHasOne.create belongsTo = ParanoidModelWithBelong.create anthorClassName = ParanoidModelWithAnthorClassNameBelong.create foreignKey = ParanoidModelWithForeignKeyBelong.create notParanoidModel = NotParanoidModelWithBelong.create hasOne.paranoid_model_with_belong = belongsTo hasOne.class_name_belong = anthorClassName hasOne.paranoid_model_with_foreign_key_belong = foreignKey hasOne.not_paranoid_model_with_belong = notParanoidModel hasOne.save! hasOne.destroy assert_equal false, hasOne.deleted_at.nil? assert_equal false, belongsTo.deleted_at.nil? # Does it restore has_one associations? newHasOne = ParanoidModelWithHasOne.with_deleted.find(hasOne.id) newHasOne.restore(:recursive => true) newHasOne.save! assert_equal true, hasOne.reload.deleted_at.nil? assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}" assert_equal true, notParanoidModel.destroyed? assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record" assert ParanoidModelWithAnthorClassNameBelong.with_deleted.reload.count != 0, "There should be an other record" assert ParanoidModelWithForeignKeyBelong.with_deleted.reload.count != 0, "There should be a foreign_key record" end def test_model_restore_with_has_one_association # setup and destroy test objects hasOne = ParanoidModelWithHasOne.create belongsTo = ParanoidModelWithBelong.create anthorClassName = ParanoidModelWithAnthorClassNameBelong.create foreignKey = ParanoidModelWithForeignKeyBelong.create notParanoidModel = NotParanoidModelWithBelong.create hasOne.paranoid_model_with_belong = belongsTo hasOne.class_name_belong = anthorClassName hasOne.paranoid_model_with_foreign_key_belong = foreignKey hasOne.not_paranoid_model_with_belong = notParanoidModel hasOne.save! hasOne.destroy assert_equal false, hasOne.deleted_at.nil? assert_equal false, belongsTo.deleted_at.nil? # Does it restore has_one associations? ParanoidModelWithHasOne.restore(hasOne.id, :recursive => true) hasOne.save! assert_equal true, hasOne.reload.deleted_at.nil? assert_equal true, belongsTo.reload.deleted_at.nil?, "#{belongsTo.deleted_at}" assert_equal true, notParanoidModel.destroyed? assert ParanoidModelWithBelong.with_deleted.reload.count != 0, "There should be a record" assert ParanoidModelWithAnthorClassNameBelong.with_deleted.reload.count != 0, "There should be an other record" assert ParanoidModelWithForeignKeyBelong.with_deleted.reload.count != 0, "There should be a foreign_key record" end def test_restore_with_nil_has_one_association # setup and destroy test object hasOne = ParanoidModelWithHasOne.create hasOne.destroy assert_equal false, hasOne.reload.deleted_at.nil? # Does it raise NoMethodException on restore of nil hasOne.restore(:recursive => true) assert hasOne.reload.deleted_at.nil? end def test_restore_with_module_scoped_has_one_association # setup and destroy test object hasOne = Namespaced::ParanoidHasOne.create hasOne.destroy assert_equal false, hasOne.reload.deleted_at.nil? # Does it raise "uninitialized constant ParanoidBelongsTo" # on restore of ParanoidHasOne? hasOne.restore(:recursive => true) assert hasOne.reload.deleted_at.nil? end # covers #185 def test_restoring_recursive_has_one_restores_correct_object hasOnes = 2.times.map { ParanoidModelWithHasOne.create } belongsTos = 2.times.map { ParanoidModelWithBelong.create } hasOnes[0].update paranoid_model_with_belong: belongsTos[0] hasOnes[1].update paranoid_model_with_belong: belongsTos[1] hasOnes.each(&:destroy) ParanoidModelWithHasOne.restore(hasOnes[1].id, :recursive => true) hasOnes.each(&:reload) belongsTos.each(&:reload) # without #185, belongsTos[0] will be restored instead of belongsTos[1] refute_nil hasOnes[0].deleted_at refute_nil belongsTos[0].deleted_at assert_nil hasOnes[1].deleted_at assert_nil belongsTos[1].deleted_at end # covers #131 def test_has_one_really_destroy_with_nil model = ParanoidModelWithHasOne.create model.really_destroy! refute ParanoidModelWithBelong.unscoped.exists?(model.id) end def test_has_one_really_destroy_with_record model = ParanoidModelWithHasOne.create { |record| record.build_paranoid_model_with_belong } model.really_destroy! refute ParanoidModelWithBelong.unscoped.exists?(model.id) end def test_observers_notified a = ParanoidModelWithObservers.create a.destroy a.restore! assert a.observers_notified.select {|args| args == [:before_restore, a]} assert a.observers_notified.select {|args| args == [:after_restore, a]} end def test_observers_not_notified_if_not_supported a = ParanoidModelWithObservers.create a.destroy a.restore! # essentially, we're just ensuring that this doesn't crash end def test_i_am_the_destroyer expected = %Q{ Sharon: "There should be a method called I_AM_THE_DESTROYER!" Ryan: "What should this method do?" Sharon: "It should fix all the spelling errors on the page!" } assert_output expected do ParanoidModel.I_AM_THE_DESTROYER! end end def test_destroy_fails_if_callback_raises_exception parent = AsplodeModel.create assert_raises(StandardError) { parent.destroy } #transaction should be rolled back, so parent NOT deleted refute parent.destroyed?, 'Parent record was destroyed, even though AR callback threw exception' end def test_destroy_fails_if_association_callback_raises_exception parent = ParentModel.create children = [] 3.times { children << parent.asplode_models.create } assert_raises(StandardError) { parent.destroy } #transaction should be rolled back, so parent and children NOT deleted refute parent.destroyed?, 'Parent record was destroyed, even though AR callback threw exception' refute children.any?(&:destroyed?), 'Child record was destroyed, even though AR callback threw exception' end def test_restore_model_with_different_connection ActiveRecord::Base.remove_connection # Disconnect the main connection a = WithDifferentConnection.create a.destroy! a.restore! # This test passes if no exception is raised ensure setup! # Reconnect the main connection end def test_restore_clear_association_cache_if_associations_present parent = ParentModel.create 3.times { parent.very_related_models.create } parent.destroy assert_equal 0, parent.very_related_models.count assert_equal 0, parent.very_related_models.size parent.restore(recursive: true) assert_equal 3, parent.very_related_models.count assert_equal 3, parent.very_related_models.size end def test_model_without_db_connection ActiveRecord::Base.remove_connection NoConnectionModel.class_eval{ acts_as_paranoid } ensure setup! end def test_restore_recursive_on_polymorphic_has_one_association parent = ParentModel.create polymorphic = PolymorphicModel.create(parent: parent) parent.destroy assert_equal 0, polymorphic.class.count parent.restore(recursive: true) assert_equal 1, polymorphic.class.count end # Ensure that we're checking parent_type when restoring def test_missing_restore_recursive_on_polymorphic_has_one_association parent = ParentModel.create polymorphic = PolymorphicModel.create(parent_id: parent.id, parent_type: 'ParanoidModel') parent.destroy polymorphic.destroy assert_equal 0, polymorphic.class.count parent.restore(recursive: true) assert_equal 0, polymorphic.class.count end def test_counter_cache_column_update_on_destroy#_and_restore_and_really_destroy parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create related_model = parent_model_with_counter_cache_column.related_models.create assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count related_model.destroy assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count end def test_callbacks_for_counter_cache_column_update_on_destroy parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create related_model = parent_model_with_counter_cache_column.related_models.create assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called) assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called) related_model.destroy assert related_model.instance_variable_get(:@after_destroy_callback_called) # assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called) end # TODO: find a fix for Rails 4.1 if ActiveRecord::VERSION::STRING !~ /\A4\.1/ def test_counter_cache_column_update_on_really_destroy parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create related_model = parent_model_with_counter_cache_column.related_models.create assert_equal 1, parent_model_with_counter_cache_column.reload.related_models_count related_model.really_destroy! assert_equal 0, parent_model_with_counter_cache_column.reload.related_models_count end end # TODO: find a fix for Rails 4.0 and 4.1 if ActiveRecord::VERSION::STRING >= '4.2' def test_callbacks_for_counter_cache_column_update_on_really_destroy! parent_model_with_counter_cache_column = ParentModelWithCounterCacheColumn.create related_model = parent_model_with_counter_cache_column.related_models.create assert_equal nil, related_model.instance_variable_get(:@after_destroy_callback_called) assert_equal nil, related_model.instance_variable_get(:@after_commit_on_destroy_callback_called) related_model.really_destroy! assert related_model.instance_variable_get(:@after_destroy_callback_called) assert related_model.instance_variable_get(:@after_commit_on_destroy_callback_called) end end private def get_featureful_model FeaturefulModel.new(:name => "not empty") end end # Helper classes class ParanoidModel < ActiveRecord::Base belongs_to :parent_model acts_as_paranoid end class FailCallbackModel < ActiveRecord::Base belongs_to :parent_model acts_as_paranoid before_destroy { |_| false } end class FeaturefulModel < ActiveRecord::Base acts_as_paranoid validates :name, :presence => true, :uniqueness => true end class PlainModel < ActiveRecord::Base end class CallbackModel < ActiveRecord::Base acts_as_paranoid before_destroy {|model| model.instance_variable_set :@destroy_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_save {|model| model.instance_variable_set :@save_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 } validate {|model| model.instance_variable_set :@validate_called, true } def remove_called_variables instance_variables.each {|name| (name.to_s.end_with?('_called')) ? remove_instance_variable(name) : nil} end end class ParentModel < ActiveRecord::Base acts_as_paranoid has_many :paranoid_models has_many :related_models has_many :very_related_models, :class_name => 'RelatedModel', dependent: :destroy has_many :non_paranoid_models, dependent: :destroy has_one :non_paranoid_model, dependent: :destroy has_many :asplode_models, dependent: :destroy has_one :polymorphic_model, as: :parent, dependent: :destroy end class ParentModelWithCounterCacheColumn < ActiveRecord::Base has_many :related_models end class RelatedModel < ActiveRecord::Base acts_as_paranoid belongs_to :parent_model belongs_to :parent_model_with_counter_cache_column, counter_cache: true after_destroy do |model| if parent_model_with_counter_cache_column && parent_model_with_counter_cache_column.reload.related_models_count == 0 model.instance_variable_set :@after_destroy_callback_called, true end end after_commit :set_after_commit_on_destroy_callback_called, on: :destroy def set_after_commit_on_destroy_callback_called if parent_model_with_counter_cache_column && parent_model_with_counter_cache_column.reload.related_models_count == 0 self.instance_variable_set :@after_commit_on_destroy_callback_called, true end end end class Employer < ActiveRecord::Base acts_as_paranoid has_many :jobs has_many :employees, :through => :jobs end class Employee < ActiveRecord::Base acts_as_paranoid has_many :jobs has_many :employers, :through => :jobs end class Job < ActiveRecord::Base acts_as_paranoid belongs_to :employer belongs_to :employee end class CustomColumnModel < ActiveRecord::Base acts_as_paranoid column: :destroyed_at end class CustomSentinelModel < ActiveRecord::Base acts_as_paranoid sentinel_value: DateTime.new(0) end class NonParanoidModel < ActiveRecord::Base end class ParanoidModelWithObservers < ParanoidModel def observers_notified @observers_notified ||= [] end def self.notify_observer(*args) observers_notified << args end end class ParanoidModelWithoutObservers < ParanoidModel self.class.send(remove_method :notify_observers) if method_defined?(:notify_observers) end # refer back to regression test for #118 class ParanoidModelWithHasOne < ParanoidModel has_one :paranoid_model_with_belong, :dependent => :destroy has_one :class_name_belong, :dependent => :destroy, :class_name => "ParanoidModelWithAnthorClassNameBelong" has_one :paranoid_model_with_foreign_key_belong, :dependent => :destroy, :foreign_key => "has_one_foreign_key_id" has_one :not_paranoid_model_with_belong, :dependent => :destroy end class ParanoidModelWithHasOneAndBuild < ActiveRecord::Base has_one :paranoid_model_with_build_belong, :dependent => :destroy validates :color, :presence => true after_validation :build_paranoid_model_with_build_belong, on: :create private def build_paranoid_model_with_build_belong super.tap { |child| child.name = "foo" } end end class ParanoidModelWithBuildBelong < ActiveRecord::Base acts_as_paranoid validates :name, :presence => true belongs_to :paranoid_model_with_has_one_and_build end class ParanoidModelWithBelong < ActiveRecord::Base acts_as_paranoid belongs_to :paranoid_model_with_has_one end class ParanoidModelWithAnthorClassNameBelong < ActiveRecord::Base acts_as_paranoid belongs_to :paranoid_model_with_has_one end class ParanoidModelWithForeignKeyBelong < ActiveRecord::Base acts_as_paranoid belongs_to :paranoid_model_with_has_one end class NotParanoidModelWithBelong < ActiveRecord::Base belongs_to :paranoid_model_with_has_one end class FlaggedModel < PlainModel acts_as_paranoid :flag_column => :is_deleted end class FlaggedModelWithCustomIndex < PlainModel acts_as_paranoid :flag_column => :is_deleted, :indexed_column => :is_deleted end class AsplodeModel < ActiveRecord::Base acts_as_paranoid before_destroy do |r| raise StandardError, 'ASPLODE!' end end class NoConnectionModel < ActiveRecord::Base end class PolymorphicModel < ActiveRecord::Base acts_as_paranoid belongs_to :parent, polymorphic: true end module Namespaced def self.table_name_prefix "namespaced_" end class ParanoidHasOne < ActiveRecord::Base acts_as_paranoid has_one :paranoid_belongs_to, dependent: :destroy end class ParanoidBelongsTo < ActiveRecord::Base acts_as_paranoid belongs_to :paranoid_has_one end end paranoia-2.1.3/CHANGELOG.md0000644000175600017570000000364112627002214014161 0ustar pravipravi# paranoia Changelog ## 2.1.0 (2015-01-23) ### Major changes * `#destroyed?` is no longer overridden. Use `#paranoia_destroyed?` for the existing behaviour. [Washington Luiz](https://github.com/huoxito) * `#persisted?` is no longer overridden. * ActiveRecord 4.0 no longer has `#destroy!` as an alias for `#really_destroy`. * `#destroy` will now raise an exception if called on a readonly record. * `#destroy` on a hard deleted record is now a successful noop. * `#destroy` on a new record will set deleted_at (previously this raised an error) * `#destroy` and `#delete` always return self when successful. ### Bug Fixes * Calling `#destroy` twice will not hard-delete records. Use `#really_destroy` if this is desired. * Fix errors on non-paranoid has_one dependent associations ## 2.0.5 (2015-01-22) ### Bug fixes * Fix restoring polymorphic has_one relationships [#189](https://github.com/radar/paranoia/pull/189) [#174](https://github.com/radar/paranoia/issues/174) [Patrick Koperwas](https://github.com/PatKoperwas) * Fix errors when restoring a model with a has_one against a non-paranoid model. [#168](https://github.com/radar/paranoia/pull/168) [Shreyas Agarwal](https://github.com/shreyas123) * Fix rspec 2 compatibility [#197](https://github.com/radar/paranoia/pull/197) [Emil Sågfors](https://github.com/lime) * Fix some deprecation warnings on rails 4.2 [Sergey Alekseev](https://github.com/sergey-alekseev) ## 2.0.4 (2014-12-02) ### Features * Add paranoia_scope as named version of default_scope [#184](https://github.com/radar/paranoia/pull/184) [Jozsef Nyitrai](https://github.com/nyjt) ### Bug Fixes * Fix initialization problems when missing table or no database connection [#186](https://github.com/radar/paranoia/issues/186) * Fix broken restore of has_one associations [#185](https://github.com/radar/paranoia/issues/185) [#171](https://github.com/radar/paranoia/pull/171) [Martin Sereinig](https://github.com/srecnig) paranoia-2.1.3/Gemfile0000644000175600017570000000054412627002214013642 0ustar pravipravisource 'https://rubygems.org' gem 'sqlite3', :platforms => [:ruby] gem 'activerecord-jdbcsqlite3-adapter', :platforms => [:jruby] platforms :rbx do gem 'rubysl', '~> 2.0' gem 'rubysl-test-unit' gem 'rubinius-developer_tools' end rails = ENV['RAILS'] || '~> 4.2.0' gem 'rails', rails # Specify your gem's dependencies in paranoia.gemspec gemspec paranoia-2.1.3/metadata.yml0000644000175600017570000000524712627002214014657 0ustar pravipravi--- !ruby/object:Gem::Specification name: paranoia version: !ruby/object:Gem::Version version: 2.1.3 platform: ruby authors: - radarlistener@gmail.com autorequire: bindir: bin cert_chain: [] date: 2015-06-17 00:00:00.000000000 Z dependencies: - !ruby/object:Gem::Dependency name: activerecord requirement: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '4.0' type: :runtime prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - "~>" - !ruby/object:Gem::Version version: '4.0' - !ruby/object:Gem::Dependency name: bundler requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 1.0.0 type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 1.0.0 - !ruby/object:Gem::Dependency name: rake requirement: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' type: :development prerelease: false version_requirements: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' description: 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 "hid" 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. email: [] executables: [] extensions: [] extra_rdoc_files: [] files: - ".gitignore" - ".travis.yml" - CHANGELOG.md - Gemfile - LICENSE - README.md - Rakefile - lib/paranoia.rb - lib/paranoia/rspec.rb - lib/paranoia/version.rb - paranoia.gemspec - test/paranoia_test.rb homepage: http://rubygems.org/gems/paranoia licenses: [] metadata: {} post_install_message: rdoc_options: [] require_paths: - lib required_ruby_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: '0' required_rubygems_version: !ruby/object:Gem::Requirement requirements: - - ">=" - !ruby/object:Gem::Version version: 1.3.6 requirements: [] rubyforge_project: paranoia rubygems_version: 2.4.8 signing_key: specification_version: 4 summary: Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much, much, much less code. test_files: [] paranoia-2.1.3/paranoia.gemspec0000644000175600017570000000250612627002214015506 0ustar pravipravi# -*- encoding: utf-8 -*- require File.expand_path("../lib/paranoia/version", __FILE__) Gem::Specification.new do |s| s.name = "paranoia" s.version = Paranoia::VERSION s.platform = Gem::Platform::RUBY s.authors = ["radarlistener@gmail.com"] s.email = [] s.homepage = "http://rubygems.org/gems/paranoia" s.summary = "Paranoia is a re-implementation of acts_as_paranoid for Rails 3, using much, much, much less code." s.description = "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 \"hid\" 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." s.required_rubygems_version = ">= 1.3.6" s.rubyforge_project = "paranoia" s.add_dependency "activerecord", "~> 4.0" s.add_development_dependency "bundler", ">= 1.0.0" s.add_development_dependency "rake" s.files = `git ls-files`.split("\n") s.executables = `git ls-files`.split("\n").map{|f| f =~ /^bin\/(.*)/ ? $1 : nil}.compact s.require_path = 'lib' end paranoia-2.1.3/lib/0000755000175600017570000000000012627002214013112 5ustar pravipraviparanoia-2.1.3/lib/paranoia/0000755000175600017570000000000012627002214014704 5ustar pravipraviparanoia-2.1.3/lib/paranoia/version.rb0000644000175600017570000000005012627002214016711 0ustar pravipravimodule Paranoia VERSION = "2.1.3" end paranoia-2.1.3/lib/paranoia/rspec.rb0000644000175600017570000000135212627002214016346 0ustar pravipravirequire 'rspec/expectations' # Validate the subject's class did call "acts_as_paranoid" RSpec::Matchers.define :act_as_paranoid do match { |subject| subject.class.ancestors.include?(Paranoia) } failure_message_proc = lambda do "expected #{subject.class} to use `acts_as_paranoid`" end failure_message_when_negated_proc = lambda do "expected #{subject.class} not to use `acts_as_paranoid`" end if respond_to?(:failure_message_when_negated) failure_message(&failure_message_proc) failure_message_when_negated(&failure_message_when_negated_proc) else # RSpec 2 compatibility: failure_message_for_should(&failure_message_proc) failure_message_for_should_not(&failure_message_when_negated_proc) end end paranoia-2.1.3/lib/paranoia.rb0000644000175600017570000001631612627002214015240 0ustar pravipravirequire 'active_record' unless defined? ActiveRecord module Paranoia @@default_sentinel_value = nil # Change default_sentinel_value in a rails initilizer def self.default_sentinel_value=(val) @@default_sentinel_value = val end def self.default_sentinel_value @@default_sentinel_value end def self.included(klazz) klazz.extend Query klazz.extend Callbacks end module Query def paranoid? ; true ; end def with_deleted if ActiveRecord::VERSION::STRING >= "4.1" unscope where: paranoia_column else all.tap { |x| x.default_scoped = false } end end def only_deleted with_deleted.where.not(paranoia_column => paranoia_sentinel_value) end alias :deleted :only_deleted def restore(id_or_ids, opts = {}) ids = Array(id_or_ids).flatten any_object_instead_of_id = ids.any? { |id| ActiveRecord::Base === id } if any_object_instead_of_id ids.map! { |id| ActiveRecord::Base === id ? id.id : id } ActiveSupport::Deprecation.warn("You are passing an instance of ActiveRecord::Base to `restore`. " \ "Please pass the id of the object by calling `.id`") end ids.map { |id| only_deleted.find(id).restore!(opts) } end end module Callbacks def self.extended(klazz) klazz.define_callbacks :restore klazz.define_singleton_method("before_restore") do |*args, &block| set_callback(:restore, :before, *args, &block) end klazz.define_singleton_method("around_restore") do |*args, &block| set_callback(:restore, :around, *args, &block) end klazz.define_singleton_method("after_restore") do |*args, &block| set_callback(:restore, :after, *args, &block) end end end def destroy transaction do run_callbacks(:destroy) do result = touch_paranoia_column if result && ActiveRecord::VERSION::STRING >= '4.2' each_counter_cached_associations do |association| foreign_key = association.reflection.foreign_key.to_sym unless destroyed_by_association && destroyed_by_association.foreign_key.to_sym == foreign_key if send(association.reflection.name) association.decrement_counters end end end end result end end end def delete touch_paranoia_column end def restore!(opts = {}) self.class.transaction do run_callbacks(:restore) do # Fixes a bug where the build would error because attributes were frozen. # This only happened on Rails versions earlier than 4.1. noop_if_frozen = ActiveRecord.version < Gem::Version.new("4.1") if (noop_if_frozen && !@attributes.frozen?) || !noop_if_frozen write_attribute paranoia_column, paranoia_sentinel_value update_column paranoia_column, paranoia_sentinel_value end restore_associated_records if opts[:recursive] end end self end alias :restore :restore! def paranoia_destroyed? send(paranoia_column) != paranoia_sentinel_value end alias :deleted? :paranoia_destroyed? private # touch paranoia column. # insert time to paranoia column. def touch_paranoia_column raise ActiveRecord::ReadOnlyRecord, "#{self.class} is marked as readonly" if readonly? if persisted? touch(paranoia_column) elsif !frozen? write_attribute(paranoia_column, current_time_from_proper_timezone) end self end # restore associated records that have been soft deleted when # we called #destroy def restore_associated_records destroyed_associations = self.class.reflect_on_all_associations.select do |association| association.options[:dependent] == :destroy end destroyed_associations.each do |association| association_data = send(association.name) unless association_data.nil? if association_data.paranoid? if association.collection? association_data.only_deleted.each { |record| record.restore(:recursive => true) } else association_data.restore(:recursive => true) end end end if association_data.nil? && association.macro.to_s == "has_one" association_class_name = association.klass.name association_foreign_key = association.foreign_key if association.type association_polymorphic_type = association.type association_find_conditions = { association_polymorphic_type => self.class.name.to_s, association_foreign_key => self.id } else association_find_conditions = { association_foreign_key => self.id } end association_class = Object.const_get(association_class_name) if association_class.paranoid? association_class.only_deleted.where(association_find_conditions).first.try!(:restore, recursive: true) end end end clear_association_cache if destroyed_associations.present? end end class ActiveRecord::Base def self.acts_as_paranoid(options={}) alias :really_destroyed? :destroyed? alias :really_delete :delete alias :destroy_without_paranoia :destroy def really_destroy! dependent_reflections = self.class.reflections.select do |name, reflection| reflection.options[:dependent] == :destroy end if dependent_reflections.any? dependent_reflections.each do |name, reflection| association_data = self.send(name) # has_one association can return nil # .paranoid? will work for both instances and classes if association_data && association_data.paranoid? if reflection.collection? association_data.with_deleted.each(&:really_destroy!) else association_data.really_destroy! end end end end write_attribute(paranoia_column, current_time_from_proper_timezone) destroy_without_paranoia end include Paranoia class_attribute :paranoia_column, :paranoia_sentinel_value self.paranoia_column = (options[:column] || :deleted_at).to_s self.paranoia_sentinel_value = options.fetch(:sentinel_value) { Paranoia.default_sentinel_value } def self.paranoia_scope where(paranoia_column => paranoia_sentinel_value) end default_scope { paranoia_scope } before_restore { self.class.notify_observers(:before_restore, self) if self.class.respond_to?(:notify_observers) } after_restore { self.class.notify_observers(:after_restore, self) if self.class.respond_to?(:notify_observers) } end # Please do not use this method in production. # Pretty please. def self.I_AM_THE_DESTROYER! # TODO: actually implement spelling error fixes puts %Q{ Sharon: "There should be a method called I_AM_THE_DESTROYER!" Ryan: "What should this method do?" Sharon: "It should fix all the spelling errors on the page!" } end def self.paranoid? ; false ; end def paranoid? ; self.class.paranoid? ; end private def paranoia_column self.class.paranoia_column end def paranoia_sentinel_value self.class.paranoia_sentinel_value end end require 'paranoia/rspec' if defined? RSpec paranoia-2.1.3/Rakefile0000644000175600017570000000024112627002214014006 0ustar pravipravirequire 'bundler' Bundler::GemHelper.install_tasks task :test do Dir['test/*_test.rb'].each do |testfile| load testfile end end task :default => :test paranoia-2.1.3/.gitignore0000644000175600017570000000005412627002214014333 0ustar pravipravipkg/* *.gem .bundle tmp .rvmrc Gemfile.lock