track_changes 0.5.0 → 0.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (40) hide show
  1. data/LICENSE +20 -20
  2. data/README.rdoc +87 -87
  3. data/TODO +4 -4
  4. data/VERSION.yml +5 -5
  5. data/lib/track_changes/audit_filter.rb +69 -69
  6. data/lib/track_changes/base.rb +9 -9
  7. data/lib/track_changes/class_methods.rb +74 -74
  8. data/lib/track_changes/configuration.rb +38 -38
  9. data/lib/track_changes/filter.rb +43 -43
  10. data/lib/track_changes/initializer.rb +18 -18
  11. data/lib/track_changes/instance_methods.rb +5 -5
  12. data/lib/track_changes/result.rb +36 -36
  13. data/lib/track_changes.rb +12 -12
  14. data/test/base_test.rb +20 -20
  15. data/test/class_methods_test.rb +29 -29
  16. data/test/filter_test.rb +73 -73
  17. data/test/functional/posts_controller_test.rb +16 -16
  18. data/test/rails_root/app/controllers/application_controller.rb +2 -2
  19. data/test/rails_root/app/controllers/posts_controller.rb +36 -36
  20. data/test/rails_root/app/models/audit.rb +4 -4
  21. data/test/rails_root/app/models/post.rb +3 -3
  22. data/test/rails_root/config/boot.rb +110 -110
  23. data/test/rails_root/config/database.yml +3 -3
  24. data/test/rails_root/config/environment.rb +7 -7
  25. data/test/rails_root/config/environments/test.rb +7 -7
  26. data/test/rails_root/config/initializers/new_rails_defaults.rb +7 -7
  27. data/test/rails_root/config/initializers/session_store.rb +4 -4
  28. data/test/rails_root/config/initializers/track_changes_setup.rb +8 -8
  29. data/test/rails_root/config/routes.rb +3 -3
  30. data/test/rails_root/db/migrate/20100115021125_create_audits.rb +16 -16
  31. data/test/rails_root/db/migrate/20100115021151_create_posts.rb +15 -15
  32. data/test/rails_root/log/test.log +377 -2494
  33. data/test/rails_root/script/console +3 -3
  34. data/test/rails_root/script/generate +3 -3
  35. data/test/result_test.rb +35 -35
  36. data/test/test_helper.rb +29 -29
  37. data/test/track_changes/audit_filter_test.rb +154 -154
  38. data/test/track_changes/configuration_test.rb +36 -36
  39. data/test/track_changes/initializer_test.rb +37 -37
  40. metadata +31 -19
data/LICENSE CHANGED
@@ -1,20 +1,20 @@
1
- Copyright (c) 2008-2010 Matt Haley
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.
1
+ Copyright (c) 2008-2010 Matt Haley
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/README.rdoc CHANGED
@@ -1,87 +1,87 @@
1
- = track_changes
2
-
3
- TrackChanges is a Rails plugin to facilitate tracking
4
- changes made to an ActiveRecord model in your
5
- Controller actions.
6
-
7
- == Why?
8
-
9
- I originally looked at the available auditing solutions
10
- and it appeared that most of them were not thread-safe.
11
-
12
- == Installation
13
-
14
- gem install track_changes
15
-
16
- == Configuration
17
-
18
- You need to have an Audit class that has a polymorphic
19
- <tt>belongs_to</tt> association to <tt>:audited</tt>. In
20
- addition, the Audit model must have a <tt>user</tt>
21
- attribute, and your controllers must respond to
22
- <tt>current_user</tt>.
23
-
24
- Example Audit class:
25
-
26
- class Audit < ActiveRecord::Base
27
- belongs_to :audited, :polymorphic => true
28
- serialize :change_set
29
- end
30
-
31
- Example Audited class:
32
-
33
- class Post < ActiveRecord::Base
34
- has_many :audits, :as => :audited
35
- end
36
-
37
- You can also tweak some of the defaults by creating an initializer
38
- in <tt>RAILS_ROOT/config/initializers/track_changes_configuration.rb</tt>
39
- and calling TrackChanges::Initializer.instance which yields a
40
- TrackChanges::Configuration object:
41
-
42
- # These are the defaults anyways
43
- TrackChanges::Initializer.instance do |c|
44
- c.audit_assocation = :audits # Calls <tt>create!</tt> on this association method
45
- c.current_user = :current_user # Controller is sent this method to obtain current user.
46
- c.ignore_nil = true # Don't crash if a model is nil.
47
- end
48
-
49
- == Controller Example
50
-
51
- In this example, after the `update` action is called,
52
- the `@post` will be compared to a previous version, and
53
- if there are any changes, an audit will be created.
54
-
55
- class PostController < ApplicationController
56
- include TrackChanges
57
-
58
- before_filter :get_post, :except => [:index, :new]
59
-
60
- # specify a single model
61
- track_changes :post
62
-
63
- # you can also specify multiple models
64
- #track_changes :post1, :post2, ...
65
-
66
- def update
67
- if @post.update_attributes(params[:post])
68
- flash[:notice] = "Success."
69
- else
70
- render :action => "edit"
71
- end
72
- end
73
-
74
- # Normal controller actions
75
- # ...
76
-
77
- protected
78
-
79
- def get_post
80
- @post = Post.find(params[:id])
81
- end
82
- end
83
-
84
-
85
- == COPYRIGHT
86
-
87
- Copyright (c) 2008-2010 Matt Haley. See LICENSE for details.
1
+ = track_changes
2
+
3
+ TrackChanges is a Rails plugin to facilitate tracking
4
+ changes made to an ActiveRecord model in your
5
+ Controller actions.
6
+
7
+ == Why?
8
+
9
+ I originally looked at the available auditing solutions
10
+ and it appeared that most of them were not thread-safe.
11
+
12
+ == Installation
13
+
14
+ gem install track_changes
15
+
16
+ == Configuration
17
+
18
+ You need to have an Audit class that has a polymorphic
19
+ <tt>belongs_to</tt> association to <tt>:audited</tt>. In
20
+ addition, the Audit model must have a <tt>user</tt>
21
+ attribute, and your controllers must respond to
22
+ <tt>current_user</tt>.
23
+
24
+ Example Audit class:
25
+
26
+ class Audit < ActiveRecord::Base
27
+ belongs_to :audited, :polymorphic => true
28
+ serialize :change_set
29
+ end
30
+
31
+ Example Audited class:
32
+
33
+ class Post < ActiveRecord::Base
34
+ has_many :audits, :as => :audited
35
+ end
36
+
37
+ You can also tweak some of the defaults by creating an initializer
38
+ in <tt>RAILS_ROOT/config/initializers/track_changes_configuration.rb</tt>
39
+ and calling TrackChanges::Initializer.instance which yields a
40
+ TrackChanges::Configuration object:
41
+
42
+ # These are the defaults anyways
43
+ TrackChanges::Initializer.instance do |c|
44
+ c.audit_assocation = :audits # Calls <tt>create!</tt> on this association method
45
+ c.current_user = :current_user # Controller is sent this method to obtain current user.
46
+ c.ignore_nil = true # Don't crash if a model is nil.
47
+ end
48
+
49
+ == Controller Example
50
+
51
+ In this example, after the `update` action is called,
52
+ the `@post` will be compared to a previous version, and
53
+ if there are any changes, an audit will be created.
54
+
55
+ class PostController < ApplicationController
56
+ include TrackChanges
57
+
58
+ before_filter :get_post, :except => [:index, :new]
59
+
60
+ # specify a single model
61
+ track_changes :post
62
+
63
+ # you can also specify multiple models
64
+ #track_changes :post1, :post2, ...
65
+
66
+ def update
67
+ if @post.update_attributes(params[:post])
68
+ flash[:notice] = "Success."
69
+ else
70
+ render :action => "edit"
71
+ end
72
+ end
73
+
74
+ # Normal controller actions
75
+ # ...
76
+
77
+ protected
78
+
79
+ def get_post
80
+ @post = Post.find(params[:id])
81
+ end
82
+ end
83
+
84
+
85
+ == COPYRIGHT
86
+
87
+ Copyright (c) 2008-2010 Matt Haley. See LICENSE for details.
data/TODO CHANGED
@@ -1,4 +1,4 @@
1
- Track Changes TODO List
2
- =======================
3
-
4
- * Check for ivars
1
+ Track Changes TODO List
2
+ =======================
3
+
4
+ * Check for ivars
data/VERSION.yml CHANGED
@@ -1,5 +1,5 @@
1
- ---
2
- :major: 0
3
- :minor: 5
4
- :patch: 0
5
- :build:
1
+ ---
2
+ :patch: 1
3
+ :major: 0
4
+ :build:
5
+ :minor: 5
@@ -1,69 +1,69 @@
1
- module TrackChanges
2
- # An around filter that will audit changes to your models.
3
- #
4
- # Example:
5
- # class OrdersController < ApplicationController
6
- # before_filter :find_order, :except => [:index, :new, :create]
7
- # around_filter AuditFilter.new(:order), :only => :update
8
- #
9
- # def update
10
- # ...
11
- # end
12
- #
13
- # protected
14
- #
15
- # def find_order
16
- # @order = Order.find(params[:id])
17
- # end
18
- # end
19
- class AuditFilter
20
- attr_accessor :cached_models, :models
21
-
22
- def initialize(*models)
23
- models.flatten!
24
- options = models.extract_options!
25
-
26
- self.cached_models = {}
27
- self.models = models
28
-
29
- @audit_accessor = options[:audit_accessor] || :audits
30
- @current_user = options[:current_user] || :current_user
31
- @ignore_nils = if options[:ignore_nil] == false
32
- false
33
- else
34
- true
35
- end
36
- end
37
-
38
- def before(controller)
39
- self.models.each do |model|
40
- instance_variable_symbol = "@#{model}".to_sym
41
- instance = controller.instance_variable_get(instance_variable_symbol)
42
- next if instance.nil? && @ignore_nils
43
-
44
- self.cached_models[instance_variable_symbol] = instance.clone
45
- end
46
- end
47
-
48
- def after(controller)
49
- self.cached_models.each_pair do |instance_variable_symbol, original_instance|
50
- new_instance = controller.instance_variable_get(instance_variable_symbol)
51
- next if new_instance.changed? # Dirty objects didn't save
52
-
53
- changes = changes_between(new_instance, original_instance)
54
-
55
- unless changes.empty?
56
- audit = new_instance.send(@audit_accessor).create!(:user => controller.send(@current_user), :change_set => changes)
57
- end
58
- end
59
- end
60
-
61
- private
62
-
63
- def changes_between(new, old)
64
- clone = old.clone
65
- clone.attributes = new.attributes
66
- clone.changes
67
- end
68
- end
69
- end
1
+ module TrackChanges
2
+ # An around filter that will audit changes to your models.
3
+ #
4
+ # Example:
5
+ # class OrdersController < ApplicationController
6
+ # before_filter :find_order, :except => [:index, :new, :create]
7
+ # around_filter AuditFilter.new(:order), :only => :update
8
+ #
9
+ # def update
10
+ # ...
11
+ # end
12
+ #
13
+ # protected
14
+ #
15
+ # def find_order
16
+ # @order = Order.find(params[:id])
17
+ # end
18
+ # end
19
+ class AuditFilter
20
+ attr_accessor :cached_models, :models
21
+
22
+ def initialize(*models)
23
+ models.flatten!
24
+ options = models.extract_options!
25
+
26
+ self.cached_models = {}
27
+ self.models = models
28
+
29
+ @audit_accessor = options[:audit_accessor] || :audits
30
+ @current_user = options[:current_user] || :current_user
31
+ @ignore_nils = if options[:ignore_nil] == false
32
+ false
33
+ else
34
+ true
35
+ end
36
+ end
37
+
38
+ def before(controller)
39
+ self.models.each do |model|
40
+ instance_variable_symbol = "@#{model}".to_sym
41
+ instance = controller.instance_variable_get(instance_variable_symbol)
42
+ next if instance.nil? && @ignore_nils
43
+
44
+ self.cached_models[instance_variable_symbol] = instance.clone
45
+ end
46
+ end
47
+
48
+ def after(controller)
49
+ self.cached_models.each_pair do |instance_variable_symbol, original_instance|
50
+ new_instance = controller.instance_variable_get(instance_variable_symbol)
51
+ next if new_instance.changed? # Dirty objects didn't save
52
+
53
+ changes = changes_between(new_instance, original_instance)
54
+
55
+ unless changes.empty?
56
+ audit = new_instance.send(@audit_accessor).create!(:user => controller.send(@current_user), :change_set => changes)
57
+ end
58
+ end
59
+ end
60
+
61
+ private
62
+
63
+ def changes_between(new, old)
64
+ clone = old.clone
65
+ clone.attributes = new.attributes
66
+ clone.changes
67
+ end
68
+ end
69
+ end
@@ -1,9 +1,9 @@
1
- require 'track_changes/instance_methods'
2
- require 'track_changes/class_methods'
3
-
4
- module TrackChanges
5
- def self.included(controller)
6
- controller.send(:include, InstanceMethods)
7
- controller.extend(ClassMethods)
8
- end
9
- end
1
+ require 'track_changes/instance_methods'
2
+ require 'track_changes/class_methods'
3
+
4
+ module TrackChanges
5
+ def self.included(controller)
6
+ controller.send(:include, InstanceMethods)
7
+ controller.extend(ClassMethods)
8
+ end
9
+ end
@@ -1,74 +1,74 @@
1
- require 'active_support'
2
- require 'track_changes/filter'
3
-
4
- module TrackChanges
5
- module ClassMethods
6
- # Create an audit of the changes made to a module during a controller action.
7
- # Some assumptions are made, primarily that the given models will have a
8
- # polymorphic association to an Audit model. An example Audit model:
9
- #
10
- # class Audit < ActiveRecord::Base
11
- # belongs_to :audited, :polymorphic => true
12
- # belongs_to :user
13
- # serialize :change_set
14
- # end
15
- #
16
- # # Example model that would be audited:
17
- # class Order < ActiveRecord::Base
18
- # has_many :audits, :as => :audited
19
- # end
20
- #
21
- # ==== Parameters
22
- #
23
- # * A symbol or many symbols of the name(s) of the instance variable to create audits for.
24
- # * An optional hash that will be passed as filter conditions to <tt>around_filter</tt>
25
- #
26
- # ==== Examples
27
- #
28
- # # Create an audit of changes made to @order during the <tt>:update</tt> action.
29
- # track_changes :order
30
- #
31
- # # Creates an audit of changes made to @order or @customer during the <tt>:update</tt> action.
32
- # track_changes :order, :customer
33
- #
34
- # # Create an audit of changes made to @order during the <tt>:update</tt> or <tt>:process</tt> actions.
35
- # track_changes :order, :only => [:update, :process]
36
- def track_changes(*args)
37
- options = args.extract_options!
38
- models = args.flatten
39
- options = [:only => :update] if options.empty?
40
-
41
- configuration = TrackChanges::Initializer.instance.configuration
42
-
43
- audit_filter = AuditFilter.new(models,
44
- :audit_accessor => configuration.audit_association,
45
- :current_user => configuration.current_user,
46
- :ignore_nil => configuration.ignore_nil)
47
- around_filter(audit_filter, options)
48
- end
49
-
50
- # Uses a combination of <tt>before_filter</tt> and <tt>after_filter</tt>
51
- # to act on changes made to a module during a controllers <tt>update</tt>
52
- # action.
53
- #
54
- # Parameters:
55
- #
56
- # * <tt>model</tt>: A symbol of the model instance name to track changes to
57
- # * <tt>only_if_changed</tt>: If true, will only yield block if changes is not empty. Defaults to <tt>true</tt>.
58
- # * <tt>options</tt>: An options hash the will be supplied to <tt>before_filter</tt> and <tt>after_filter</tt>. Defaults to <tt>:only => :update</tt>.
59
- # * <tt>&block</tt>: The supplied block is called with an instance of Result as its parameter.
60
- def track_changes_to(models, only_if_changed = true, options = {:only => :update}, &block)
61
- warn "[DEPRECATED] track_changes_to is deprecated. Use track_changes instead"
62
- append_before_filter(options) do |controller|
63
- track_filter = Filter.new(models, only_if_changed, block)
64
- controller.track_changes_filter = track_filter
65
-
66
- track_filter.before(controller)
67
- end
68
-
69
- append_after_filter(options)do |controller|
70
- controller.track_changes_filter.after(controller)
71
- end
72
- end
73
- end
74
- end
1
+ require 'active_support'
2
+ require 'track_changes/filter'
3
+
4
+ module TrackChanges
5
+ module ClassMethods
6
+ # Create an audit of the changes made to a module during a controller action.
7
+ # Some assumptions are made, primarily that the given models will have a
8
+ # polymorphic association to an Audit model. An example Audit model:
9
+ #
10
+ # class Audit < ActiveRecord::Base
11
+ # belongs_to :audited, :polymorphic => true
12
+ # belongs_to :user
13
+ # serialize :change_set
14
+ # end
15
+ #
16
+ # # Example model that would be audited:
17
+ # class Order < ActiveRecord::Base
18
+ # has_many :audits, :as => :audited
19
+ # end
20
+ #
21
+ # ==== Parameters
22
+ #
23
+ # * A symbol or many symbols of the name(s) of the instance variable to create audits for.
24
+ # * An optional hash that will be passed as filter conditions to <tt>around_filter</tt>
25
+ #
26
+ # ==== Examples
27
+ #
28
+ # # Create an audit of changes made to @order during the <tt>:update</tt> action.
29
+ # track_changes :order
30
+ #
31
+ # # Creates an audit of changes made to @order or @customer during the <tt>:update</tt> action.
32
+ # track_changes :order, :customer
33
+ #
34
+ # # Create an audit of changes made to @order during the <tt>:update</tt> or <tt>:process</tt> actions.
35
+ # track_changes :order, :only => [:update, :process]
36
+ def track_changes(*args)
37
+ options = args.extract_options!
38
+ models = args.flatten
39
+ options = {:only => :update} if options.empty?
40
+
41
+ configuration = TrackChanges::Initializer.instance.configuration
42
+
43
+ audit_filter = AuditFilter.new(models,
44
+ :audit_accessor => configuration.audit_association,
45
+ :current_user => configuration.current_user,
46
+ :ignore_nil => configuration.ignore_nil)
47
+ around_filter(audit_filter, options)
48
+ end
49
+
50
+ # Uses a combination of <tt>before_filter</tt> and <tt>after_filter</tt>
51
+ # to act on changes made to a module during a controllers <tt>update</tt>
52
+ # action.
53
+ #
54
+ # Parameters:
55
+ #
56
+ # * <tt>model</tt>: A symbol of the model instance name to track changes to
57
+ # * <tt>only_if_changed</tt>: If true, will only yield block if changes is not empty. Defaults to <tt>true</tt>.
58
+ # * <tt>options</tt>: An options hash the will be supplied to <tt>before_filter</tt> and <tt>after_filter</tt>. Defaults to <tt>:only => :update</tt>.
59
+ # * <tt>&block</tt>: The supplied block is called with an instance of Result as its parameter.
60
+ def track_changes_to(models, only_if_changed = true, options = {:only => :update}, &block)
61
+ warn "[DEPRECATED] track_changes_to is deprecated. Use track_changes instead"
62
+ append_before_filter(options) do |controller|
63
+ track_filter = Filter.new(models, only_if_changed, block)
64
+ controller.track_changes_filter = track_filter
65
+
66
+ track_filter.before(controller)
67
+ end
68
+
69
+ append_after_filter(options)do |controller|
70
+ controller.track_changes_filter.after(controller)
71
+ end
72
+ end
73
+ end
74
+ end
@@ -1,38 +1,38 @@
1
- module TrackChanges
2
- class Configuration
3
- # The association used to create an audit. Defaults to
4
- # <tt>:audits</tt>
5
- #
6
- # Example:
7
- # :audits # => Call model.audits.create
8
- # :changes # => Call model.changes.create
9
- attr_accessor :audit_association
10
-
11
- # The controller method called to obtain the current user.
12
- # Defaults to <tt>:current_user</tt>
13
- attr_accessor :current_user
14
-
15
- # Ignore if the audited item is nil. Defaults to <tt>true</tt>.
16
- attr_accessor :ignore_nil
17
-
18
- def initialize
19
- self.audit_association = default_audit_association
20
- self.current_user = default_current_user
21
- self.ignore_nil = default_ignore_nil
22
- end
23
-
24
- private
25
-
26
- def default_audit_association
27
- :audits
28
- end
29
-
30
- def default_current_user
31
- :current_user
32
- end
33
-
34
- def default_ignore_nil
35
- true
36
- end
37
- end
38
- end
1
+ module TrackChanges
2
+ class Configuration
3
+ # The association used to create an audit. Defaults to
4
+ # <tt>:audits</tt>
5
+ #
6
+ # Example:
7
+ # :audits # => Call model.audits.create
8
+ # :changes # => Call model.changes.create
9
+ attr_accessor :audit_association
10
+
11
+ # The controller method called to obtain the current user.
12
+ # Defaults to <tt>:current_user</tt>
13
+ attr_accessor :current_user
14
+
15
+ # Ignore if the audited item is nil. Defaults to <tt>true</tt>.
16
+ attr_accessor :ignore_nil
17
+
18
+ def initialize
19
+ self.audit_association = default_audit_association
20
+ self.current_user = default_current_user
21
+ self.ignore_nil = default_ignore_nil
22
+ end
23
+
24
+ private
25
+
26
+ def default_audit_association
27
+ :audits
28
+ end
29
+
30
+ def default_current_user
31
+ :current_user
32
+ end
33
+
34
+ def default_ignore_nil
35
+ true
36
+ end
37
+ end
38
+ end