culturecode-track_changes 0.0.1 → 0.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d9f210dc9b044e9606eaceda2cb73ee6b16d41ba
4
- data.tar.gz: 381b4764ef7f663a87482ce71d91510769a422b2
3
+ metadata.gz: 07ad7f3aeec94be71f57d6d3e0b3726ab473b8f4
4
+ data.tar.gz: 3171e12d387c900f3ee7e1892d45c51bc96ab11e
5
5
  SHA512:
6
- metadata.gz: ebe1afa939c705490216f2b144a359cf44d18c59d694745d6d314ca3e848e70e97f8831a5c743f4be10ac2e824c1ac2c69c4288389eef68a1e6eb6340997c9cb
7
- data.tar.gz: 235713afc3708a6b5208350fb201e53cde080630779003f14a4034704cf248cbca2e0e390a9bf4b2be3584924c14b98842b42525d3472f987d2d93fc3a0b749f
6
+ metadata.gz: c2ef18640299c7abaf104f0c79552de9cd0c7334199500dc0015450a8bd626a1c1741f51871ea22f69ad9a372a9d1631ebdaf794012948715a99ca61ef1e977c
7
+ data.tar.gz: 58fa61d8192b607a59c5ab10392667d2be9c10193b836a75ad9395869236313919d3b3d997f0a068760f3308dea32be6bdbe6dd810b6467776b69e2b7669903a
data/README.md CHANGED
@@ -26,8 +26,6 @@ end
26
26
 
27
27
  ## Usage
28
28
 
29
- In your model
30
-
31
29
  ```ruby
32
30
  class Person < ActiveRecord::Base
33
31
  tracks_changes # may also pass an options hash
@@ -42,3 +40,23 @@ By default all model attributes are tracked, except the primary_key, usually ```
42
40
  - ```:methods``` accepts a field name or array of field names to track in addition to the default fields
43
41
  - ```:track_timestamps``` accepts a boolean, enabling or disabling tracking of ```created_at``` and ```updated_at```
44
42
  - ```:track_primary_key``` accepts a boolean, enabling or disabling tracking of the model's primary key
43
+
44
+ ### Attribution
45
+ Changes can be attributed to a particular source. The source is saved as a string
46
+ in the ```:changes_by column``` of the record. If given an instance of ActiveRecord::Base,
47
+ the record's id will be used.
48
+
49
+ ```ruby
50
+ # Inline attribution
51
+ person.save(:changes_by => 'Joe Changems')
52
+
53
+ # Block-level attribution
54
+ attribute_changes_to 'Joe Changems' do
55
+ person.save
56
+ end
57
+
58
+ # Controller-level attribution
59
+ class MyController < ApplicationController
60
+ attribute_changes_to :current_user
61
+ end
62
+ ```
@@ -11,9 +11,20 @@ module TrackChanges
11
11
  end
12
12
  end
13
13
 
14
+ #
15
+ # Generate a human readable sentence for a change in a TrackChanges::Diff
16
+ #
17
+ # diff - a TrackChanges::Diff object
18
+ # field - the specific field of the diff (e.g. collection_id)
19
+ # changes - an array of the previous and current value for the field
20
+ # link_models - an array of classes of models that should generate as in-sentence links
21
+ #
14
22
  def diff_change_sentence(diff, field, changes, link_models = [])
15
23
  from, to = changes.is_a?(Array) ? changes : [nil, changes]
16
- # return if diff.action == 'destroy'
24
+
25
+ from.reject!(&:blank?) if from.is_a?(Array)
26
+ to.reject!(&:blank?) if to.is_a?(Array)
27
+
17
28
  return if from.blank? && to.blank?
18
29
 
19
30
  if record = diff.record
@@ -22,8 +33,8 @@ module TrackChanges
22
33
  end
23
34
 
24
35
  if reflection
25
- from = reflection.klass.find(from) if from.present?
26
- to = reflection.klass.find(to) if to.present?
36
+ from = reflection.klass.find_by_id(from) || content_tag(:span, 'DELETED', :class => 'deleted', :title => "This #{field_name} has been deleted") if from.present?
37
+ to = reflection.klass.find_by_id(to) || content_tag(:span, 'DELETED', :class => 'deleted', :title => "This #{field_name} has been deleted") if to.present?
27
38
  end
28
39
 
29
40
  if from.blank?
@@ -8,6 +8,11 @@ module TrackChanges
8
8
 
9
9
  before_save :capture_record_state
10
10
 
11
+ # Returns a hash of the current values for all tracked fields on the record
12
+ def self.record_state(record)
13
+ Hash[record.class.track_changes_fields.collect {|method_name| [method_name, record.send(method_name)] }]
14
+ end
15
+
11
16
  # Creates a diff object that shows the changes between this snapshot and the record's state
12
17
  def create_diff(diff_attributes = {})
13
18
  record_state = self.class.record_state(record)
@@ -33,10 +38,5 @@ module TrackChanges
33
38
  def capture_record_state
34
39
  self.state = self.class.record_state(record)
35
40
  end
36
-
37
- # Returns a hash of the current values for all tracked fields on the record
38
- def self.record_state(record)
39
- Hash[record.class.track_changes_fields.collect {|method_name| [method_name, record.send(method_name)] }]
40
- end
41
41
  end
42
42
  end
@@ -1 +1 @@
1
- ActiveRecord::Base.send :extend, TrackChanges::ActsMethod
1
+ ActiveRecord::Base.send :extend, TrackChanges::Model::Base
@@ -0,0 +1 @@
1
+ ApplicationController.send :extend, TrackChanges::Controller::Base
@@ -0,0 +1,13 @@
1
+ module TrackChanges
2
+ mattr_accessor :default_attribution
3
+
4
+ # Set the source used for implict changes_by attribution
5
+ # for the duration of the block
6
+ def self.with_changes_attributed_to(new_source, &block)
7
+ old_source = self.default_attribution
8
+ self.default_attribution = new_source
9
+ block.call
10
+ ensure
11
+ self.default_attribution = old_source
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module TrackChanges
2
+ module Controller
3
+ module Base
4
+ def attribute_changes_to(method_name)
5
+ around_action do |controller, action_block|
6
+ TrackChanges.with_changes_attributed_to controller.send(method_name), &action_block
7
+ end
8
+ end
9
+ end
10
+ end
11
+ end
@@ -1,4 +1,6 @@
1
- require 'track_changes/track_changes'
1
+ require 'track_changes/model'
2
+ require 'track_changes/controller'
3
+ require 'track_changes/attribution'
2
4
 
3
5
  module TrackChanges
4
6
  class Engine < ::Rails::Engine
@@ -0,0 +1,69 @@
1
+ module TrackChanges
2
+ module Model
3
+ module Base
4
+ def tracks_changes(options = {})
5
+ extend ClassMethods
6
+ include InstanceMethods
7
+
8
+ class_attribute :track_changes_options
9
+ self.track_changes_options = options
10
+
11
+ attr_accessor :track_changes # Faux attribute to allow disabling of change tracking on this record
12
+ attr_writer :track_changes_by # Faux attribute to store who made the changes so we can save it in the diff
13
+
14
+ has_one :snapshot, :as => :record, :class_name => 'TrackChanges::Snapshot' # A representation of this record as it was last saved
15
+ has_many :diffs, :as => :record, :class_name => 'TrackChanges::Diff' # A representation of changes made between saves through this record's lifetime
16
+
17
+ after_save :persist_tracked_changes
18
+ end
19
+ end
20
+
21
+ module ClassMethods
22
+ # Returns the method names to call to fetch the fields tracked for changes
23
+ def track_changes_fields
24
+ fields = Array(track_changes_options[:only]).collect(&:to_s).presence || self.attribute_names
25
+ fields -= Array(track_changes_options[:except]).collect(&:to_s)
26
+ fields += Array(track_changes_options[:methods]).collect(&:to_s)
27
+ fields -= ['created_at', 'updated_at'] unless track_changes_options[:track_timestamps]
28
+ fields -= [primary_key] unless track_changes_options[:track_primary_key]
29
+ end
30
+
31
+ # Create snapshots for all records so that the next changes made are captured
32
+ # This can be used to init track changes on existing records
33
+ def snapshot_all
34
+ # Update existing snapshots
35
+ joins(:snapshot).find_each {|record| record.snapshot.update }
36
+ # Create new snapshots
37
+ where.not(:id => joins(:snapshot)).find_each(&:create_snapshot)
38
+ end
39
+ end
40
+
41
+ module InstanceMethods
42
+ private
43
+
44
+ def track_changes_by
45
+ @track_changes_by || TrackChanges.default_attribution
46
+ end
47
+
48
+ # Compares the last tracked changes to the current state and saves a diff of the changes
49
+ def persist_tracked_changes
50
+ return if track_changes == false
51
+
52
+ new_record = id_was.blank?
53
+ action = new_record ? 'create' : 'update'
54
+ changes_by = track_changes_by.is_a?(ActiveRecord::Base) ? track_changes_by.id : track_changes_by
55
+
56
+ if snapshot
57
+ snapshot.create_diff(:action => action, :changes_by => changes_by)
58
+ snapshot.update
59
+ elsif new_record
60
+ create_snapshot
61
+ snapshot.create_diff(:action => action, :changes_by => changes_by, :from => {}, :to => snapshot.state)
62
+ else # We started tracking changes after the item was created
63
+ create_snapshot
64
+ snapshot.create_diff(:action => action, :changes_by => changes_by, :from => {})
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -1,3 +1,3 @@
1
1
  module TrackChanges
2
- VERSION = "0.0.1"
2
+ VERSION = "0.1.0"
3
3
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: culturecode-track_changes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Jakobsen, Ryan Wallace
@@ -53,11 +53,14 @@ files:
53
53
  - app/models/track_changes/diff.rb
54
54
  - app/models/track_changes/snapshot.rb
55
55
  - config/initializers/extend_activerecord.rb
56
+ - config/initializers/extend_application_controller.rb
56
57
  - config/routes.rb
57
58
  - lib/tasks/track_changes_tasks.rake
58
59
  - lib/track_changes.rb
60
+ - lib/track_changes/attribution.rb
61
+ - lib/track_changes/controller.rb
59
62
  - lib/track_changes/engine.rb
60
- - lib/track_changes/track_changes.rb
63
+ - lib/track_changes/model.rb
61
64
  - lib/track_changes/version.rb
62
65
  homepage: https://github.com/culturecode/track_changes
63
66
  licenses:
@@ -1,54 +0,0 @@
1
- module TrackChanges
2
- module ActsMethod
3
- def tracks_changes(options = {})
4
- extend ClassMethods
5
- include InstanceMethods
6
-
7
- class_attribute :track_changes_options
8
- self.track_changes_options = options
9
-
10
- attr_accessor :track_changes # Faux attribute to allow disabling of change tracking on this record
11
- attr_accessor :track_changes_by # Faux attribute to store who made the changes so we can save it in the diff
12
-
13
- has_one :snapshot, :as => :record, :class_name => 'TrackChanges::Snapshot' # A representation of this record as it was last saved
14
- has_many :diffs, :as => :record, :class_name => 'TrackChanges::Diff' # A representation of changes made between saves through this record's lifetime
15
-
16
- after_save :persist_tracked_changes
17
- end
18
- end
19
-
20
- module ClassMethods
21
- # Returns the method names to call to fetch the fields tracked for changes
22
- def track_changes_fields
23
- fields = Array(track_changes_options[:only]).collect(&:to_s).presence || self.attribute_names
24
- fields -= Array(track_changes_options[:except]).collect(&:to_s)
25
- fields += Array(track_changes_options[:methods]).collect(&:to_s)
26
- fields -= ['created_at', 'updated_at'] unless track_changes_options[:track_timestamps]
27
- fields -= [primary_key] unless track_changes_options[:track_primary_key]
28
- end
29
- end
30
-
31
- module InstanceMethods
32
- private
33
-
34
- # Compares the last tracked changes to the current state and saves a diff of the changes
35
- def persist_tracked_changes
36
- return if track_changes == false
37
-
38
- new_record = id_was.blank?
39
- action = new_record ? 'create' : 'update'
40
- changes_by = track_changes_by.is_a?(ActiveRecord::Base) ? track_changes_by.id : track_changes_by
41
-
42
- if snapshot
43
- snapshot.create_diff(:action => action, :changes_by => changes_by)
44
- snapshot.update
45
- elsif new_record
46
- create_snapshot
47
- snapshot.create_diff(:action => action, :changes_by => changes_by, :from => {}, :to => snapshot.state)
48
- else # We started tracking changes after the item was created
49
- create_snapshot
50
- snapshot.create_diff(:action => action, :changes_by => changes_by, :from => {})
51
- end
52
- end
53
- end
54
- end