JackDanger-permanent_records 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
data/MIT-LICENSE ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 [name of plugin creator]
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,18 @@
1
+ MIT-LICENSE
2
+ Manifest.txt
3
+ README
4
+ Rakefile
5
+ init.rb
6
+ install.rb
7
+ lib/permanent_records.rb
8
+ tasks/permanent_records_tasks.rake
9
+ test/cached_values_test.rb
10
+ test/database.yml
11
+ test/hole.rb
12
+ test/kitty.rb
13
+ test/mole.rb
14
+ test/muskrat.rb
15
+ test/permanent_records_test.rb
16
+ test/schema.rb
17
+ test/test_helper.rb
18
+ uninstall.rb
data/README ADDED
@@ -0,0 +1,22 @@
1
+ PermanentRecords
2
+ ================
3
+
4
+ This plugin prevents any of your records from being destroyed casually.
5
+ Any model with a deleted_at datetime column will have that column set rather than being deleted.
6
+
7
+ Usage
8
+ =======
9
+
10
+ User.find(3).destroy # sets the 'deleted_at' attribute to Time.now and returns a frozen record
11
+ User.find(3).destroy(:force) # executes the real destroy method, the record will be removed from the database
12
+ User.delete_all # bye bye everything
13
+
14
+ There are also two named scopes provided for easily searching deleted and not deleted records:
15
+
16
+ User.send :with_deleted { User.find(:all) } # only returns deleted records.
17
+ User.send :with_not_deleted { User.find(:all) } # you guessed it.
18
+
19
+ These are named so as to work smoothly with other scoping plugins like scope_out.
20
+
21
+
22
+ Copyright (c) 2008 Jack Danger Canty of adPickles Inc., released under the MIT license
data/Rakefile ADDED
@@ -0,0 +1,12 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+ require File.dirname(__FILE__) + '/lib/permanent_records'
6
+
7
+ Hoe.new('permanent_records', PermanentRecords::VERSION) do |p|
8
+ p.summary = "Soft-delete your ActiveRecord data."
9
+ p.developer('Jack Danger Canty', 'gems@6brand.com')
10
+ end
11
+
12
+ # vim: syntax=Ruby
data/init.rb ADDED
@@ -0,0 +1,3 @@
1
+ require 'permanent_records'
2
+
3
+ ActiveRecord::Base.send :include, PermanentRecords
data/install.rb ADDED
File without changes
@@ -0,0 +1,86 @@
1
+ module PermanentRecords
2
+ VERSION = '1.0.1'
3
+ def self.included(base)
4
+ if base.respond_to?(:named_scope)
5
+ base.named_scope :deleted, :conditions => {:deleted_at => true}
6
+ base.named_scope :not_deleted, :conditions => { :deleted_at => nil }
7
+ else
8
+ base.extend LegacyScopes
9
+ end
10
+ base.send :include, InstanceMethods
11
+ base.define_callbacks :before_revive, :after_revive
12
+ base.alias_method_chain :destroy, :permanent_record_force
13
+ base.alias_method_chain :destroy_without_callbacks, :permanent_record
14
+ end
15
+
16
+ module LegacyScopes
17
+ def with_deleted
18
+ with_scope :find => {:conditions => "#{quoted_table_name}.deleted_at IS NOT NULL"} do
19
+ yield
20
+ end
21
+ end
22
+
23
+ def with_not_deleted
24
+ with_scope :find => {:conditions => "#{quoted_table_name}.deleted_at IS NULL"} do
25
+ yield
26
+ end
27
+ end
28
+
29
+ # this next bit is basically stolen from the scope_out plugin
30
+ [:deleted, :not_deleted].each do |name|
31
+ define_method "find_#{name}" do |*args|
32
+ send("with_#{name}") { find(*args) }
33
+ end
34
+
35
+ define_method "count_#{name}" do |*args|
36
+ send("with_#{name}") { count(*args) }
37
+ end
38
+
39
+ define_method "calculate_#{name}" do |*args|
40
+ send("with_#{name}") { calculate(*args) }
41
+ end
42
+
43
+ define_method "find_all_#{name}" do |*args|
44
+ send("with_#{name}") { find(:all, *args) }
45
+ end
46
+ end
47
+ end
48
+
49
+ module InstanceMethods
50
+
51
+ def is_permanent?
52
+ respond_to?(:deleted_at)
53
+ end
54
+
55
+ def deleted?
56
+ deleted_at if is_permanent?
57
+ end
58
+
59
+ def revive
60
+ run_callbacks :before_revive
61
+ set_deleted_at nil
62
+ run_callbacks :after_revive
63
+ self
64
+ end
65
+
66
+ def set_deleted_at(value)
67
+ return self unless is_permanent?
68
+ record = self.class.find(id)
69
+ record.update_attribute(:deleted_at, value)
70
+ @attributes, @attributes_cache = record.attributes, record.attributes
71
+ end
72
+
73
+ def destroy_with_permanent_record_force(force = nil)
74
+ @force_permanent_record_destroy = (:force == force)
75
+ destroy_without_permanent_record_force
76
+ end
77
+
78
+ def destroy_without_callbacks_with_permanent_record
79
+ return destroy_without_callbacks_without_permanent_record if @force_permanent_record_destroy || !is_permanent?
80
+ unless deleted? || new_record?
81
+ set_deleted_at Time.now
82
+ end
83
+ self
84
+ end
85
+ end
86
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :permanent_records do
3
+ # # Task goes here
4
+ # end
data/test/database.yml ADDED
@@ -0,0 +1,18 @@
1
+ sqlite:
2
+ :adapter: sqlite
3
+ :dbfile: plugin.sqlite.db
4
+ sqlite3:
5
+ :adapter: sqlite3
6
+ :dbfile: ":memory:"
7
+ postgresql:
8
+ :adapter: postgresql
9
+ :username: postgres
10
+ :password: postgres
11
+ :database: plugin_test
12
+ :min_messages: ERROR
13
+ mysql:
14
+ :adapter: mysql
15
+ :host: localhost
16
+ :username: rails
17
+ :password:
18
+ :database: plugin_test
data/test/hole.rb ADDED
@@ -0,0 +1,6 @@
1
+ class Hole < ActiveRecord::Base
2
+ # muskrats are permanent
3
+ has_many :muskrats, :dependent => :destroy
4
+ # moles are not permanent
5
+ has_many :moles, :dependent => :destroy
6
+ end
data/test/kitty.rb ADDED
@@ -0,0 +1,2 @@
1
+ class Kitty < ActiveRecord::Base
2
+ end
data/test/mole.rb ADDED
@@ -0,0 +1,3 @@
1
+ class Mole < ActiveRecord::Base
2
+ belongs_to :hole
3
+ end
data/test/muskrat.rb ADDED
@@ -0,0 +1,3 @@
1
+ class Muskrat < ActiveRecord::Base
2
+ belongs_to :hole
3
+ end
@@ -0,0 +1,110 @@
1
+ require 'test/unit'
2
+ require File.expand_path(File.dirname(__FILE__) + "/test_helper")
3
+
4
+ %w(hole mole muskrat kitty).each do |a|
5
+ require File.expand_path(File.dirname(__FILE__) + "/" + a)
6
+ end
7
+
8
+ class PermanentRecordsTest < Test::Unit::TestCase
9
+
10
+ def setup
11
+ super
12
+ Muskrat.delete_all
13
+ @active = Muskrat.create!(:name => 'Wakko')
14
+ @deleted = Muskrat.create!(:name => 'Yakko', :deleted_at => 4.days.ago)
15
+ @the_girl = Muskrat.create!(:name => 'Dot')
16
+ Kitty.delete_all
17
+ @kitty = Kitty.create!(:name => 'Meow Meow')
18
+ @hole = Hole.create(:number => 14)
19
+ @mole = @hole.muskrats.create(:name => "Steady Rat")
20
+ @mole = @hole.moles.create(:name => "Grabowski")
21
+ end
22
+
23
+ def teardown
24
+ setup
25
+ end
26
+
27
+ def test_destroy_should_return_the_record
28
+ muskrat = @active
29
+ assert_equal muskrat, muskrat.destroy
30
+ end
31
+
32
+ def test_revive_should_return_the_record
33
+ muskrat = @deleted
34
+ assert_equal muskrat, muskrat.destroy
35
+ end
36
+
37
+ def test_destroy_should_set_deleted_at_attribute
38
+ assert @active.destroy.deleted_at
39
+ end
40
+
41
+ def test_destroy_should_save_deleted_at_attribute
42
+ assert Muskrat.find(@active.destroy.id).deleted_at
43
+ end
44
+
45
+ def test_destroy_should_not_really_remove_the_record
46
+ assert Muskrat.find(@active.destroy.id)
47
+ end
48
+
49
+ def test_destroy_should_recognize_a_force_parameter
50
+ assert_raises(ActiveRecord::RecordNotFound) { @active.destroy(:force).reload }
51
+ end
52
+
53
+ def test_destroy_should_ignore_other_parameters
54
+ assert Muskrat.find(@active.destroy(:hula_dancer).id)
55
+ end
56
+
57
+ def test_revive_should_unfreeze_record
58
+ assert !@deleted.revive.frozen?
59
+ end
60
+
61
+ def test_revive_should_unset_deleted_at
62
+ assert !@deleted.revive.deleted_at
63
+ end
64
+
65
+ def test_revive_should_make_deleted_return_false
66
+ assert !@deleted.revive.deleted?
67
+ end
68
+
69
+ def test_deleted_returns_true_for_deleted_records
70
+ assert @deleted.deleted?
71
+ end
72
+
73
+ def test_destroy_returns_record_with_modified_attributes
74
+ assert @active.destroy.deleted?
75
+ end
76
+
77
+ def test_revive_and_destroy_should_be_chainable
78
+ assert @active.destroy.revive.destroy.destroy.revive.revive.destroy.deleted?
79
+ assert !@deleted.destroy.revive.revive.destroy.destroy.revive.deleted?
80
+ end
81
+
82
+ def test_with_deleted_limits_scope_to_deleted_records
83
+ assert Muskrat.deleted.all?(&:deleted?)
84
+ end
85
+
86
+ def test_with_not_deleted_limits_scope_to_not_deleted_records
87
+ assert !Muskrat.not_deleted.any?(&:deleted?)
88
+ end
89
+
90
+ def test_models_without_a_deleted_at_column_should_destroy_as_normal
91
+ assert_raises(ActiveRecord::RecordNotFound) {@kitty.destroy.reload}
92
+ end
93
+
94
+ def test_dependent_non_permanent_records_should_be_destroyed
95
+ assert @hole.is_permanent?
96
+ assert !@hole.moles.first.is_permanent?
97
+ assert_difference "Mole.count", -1 do
98
+ @hole.destroy
99
+ end
100
+ end
101
+
102
+ def test_dependent_permanent_records_should_be_marked_as_deleted
103
+ assert @hole.is_permanent?
104
+ assert @hole.muskrats.first.is_permanent?
105
+ assert_no_difference "Muskrat.count" do
106
+ @hole.destroy
107
+ end
108
+ assert @hole.muskrats.first.deleted?
109
+ end
110
+ end
data/test/schema.rb ADDED
@@ -0,0 +1,23 @@
1
+ ActiveRecord::Schema.define(:version => 1) do
2
+
3
+ create_table :muskrats do |t|
4
+ t.column :name, :string
5
+ t.column :deleted_at, :datetime
6
+ t.references :hole
7
+ end
8
+
9
+ create_table :kitties do |t|
10
+ t.column :name, :string
11
+ end
12
+
13
+ create_table :holes do |t|
14
+ t.integer :number
15
+ t.datetime :deleted_at
16
+ end
17
+
18
+ create_table :moles do |t|
19
+ t.string :name
20
+ t.references :hole
21
+ end
22
+
23
+ end
@@ -0,0 +1,39 @@
1
+ # Include this file in your test by copying the following line to your test:
2
+ # require File.expand_path(File.dirname(__FILE__) + "/test_helper")
3
+
4
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
5
+ RAILS_ROOT = File.dirname(__FILE__)
6
+
7
+ require 'rubygems'
8
+ require 'test/unit'
9
+ require 'active_record'
10
+ require 'active_record/fixtures'
11
+ require "#{File.dirname(__FILE__)}/../init"
12
+ require File.expand_path(File.dirname(__FILE__) + "/muskrat")
13
+
14
+ config = YAML::load(IO.read(File.dirname(__FILE__) + '/database.yml'))
15
+ ActiveRecord::Base.logger = Logger.new(File.dirname(__FILE__) + "/debug.log")
16
+ ActiveRecord::Base.establish_connection(config[ENV['DB'] || 'sqlite3'])
17
+
18
+ load(File.dirname(__FILE__) + "/schema.rb") if File.exist?(File.dirname(__FILE__) + "/schema.rb")
19
+
20
+ Test::Unit::TestCase.fixture_path = File.dirname(__FILE__) + "/fixtures/"
21
+ $LOAD_PATH.unshift(Test::Unit::TestCase.fixture_path)
22
+
23
+ class Test::Unit::TestCase #:nodoc:
24
+ # def create_fixtures(*table_names)
25
+ # if block_given?
26
+ # Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names) { yield }
27
+ # else
28
+ # Fixtures.create_fixtures(Test::Unit::TestCase.fixture_path, table_names)
29
+ # end
30
+ # end
31
+
32
+ # Turn off transactional fixtures if you're working with MyISAM tables in MySQL
33
+ self.use_transactional_fixtures = true
34
+
35
+ # Instantiated fixtures are slow, but give you @david where you otherwise would need people(:david)
36
+ self.use_instantiated_fixtures = false
37
+
38
+ # Add more helper methods to be used by all tests here...
39
+ end
data/uninstall.rb ADDED
@@ -0,0 +1 @@
1
+ # Uninstall hook code here
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: JackDanger-permanent_records
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Jack Danger Canty
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-03-19 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: hoe
17
+ type: :development
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: 1.11.0
24
+ version:
25
+ description:
26
+ email:
27
+ - gems@6brand.com
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - Manifest.txt
34
+ files:
35
+ - MIT-LICENSE
36
+ - Manifest.txt
37
+ - README
38
+ - Rakefile
39
+ - init.rb
40
+ - install.rb
41
+ - lib/permanent_records.rb
42
+ - tasks/permanent_records_tasks.rake
43
+ - test/cached_values_test.rb
44
+ - test/database.yml
45
+ - test/hole.rb
46
+ - test/kitty.rb
47
+ - test/mole.rb
48
+ - test/muskrat.rb
49
+ - test/permanent_records_test.rb
50
+ - test/schema.rb
51
+ - test/test_helper.rb
52
+ - uninstall.rb
53
+ has_rdoc: true
54
+ homepage:
55
+ post_install_message:
56
+ rdoc_options:
57
+ - --main
58
+ - README.txt
59
+ require_paths:
60
+ - lib
61
+ required_ruby_version: !ruby/object:Gem::Requirement
62
+ requirements:
63
+ - - ">="
64
+ - !ruby/object:Gem::Version
65
+ version: "0"
66
+ version:
67
+ required_rubygems_version: !ruby/object:Gem::Requirement
68
+ requirements:
69
+ - - ">="
70
+ - !ruby/object:Gem::Version
71
+ version: "0"
72
+ version:
73
+ requirements: []
74
+
75
+ rubyforge_project: permanent_records
76
+ rubygems_version: 1.2.0
77
+ signing_key:
78
+ specification_version: 2
79
+ summary: Soft-delete your ActiveRecord data.
80
+ test_files:
81
+ - test/test_helper.rb