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 +4 -4
- data/README.md +20 -2
- data/app/helpers/track_changes/diff_helper.rb +14 -3
- data/app/models/track_changes/snapshot.rb +5 -5
- data/config/initializers/extend_activerecord.rb +1 -1
- data/config/initializers/extend_application_controller.rb +1 -0
- data/lib/track_changes/attribution.rb +13 -0
- data/lib/track_changes/controller.rb +11 -0
- data/lib/track_changes/engine.rb +3 -1
- data/lib/track_changes/model.rb +69 -0
- data/lib/track_changes/version.rb +1 -1
- metadata +5 -2
- data/lib/track_changes/track_changes.rb +0 -54
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 07ad7f3aeec94be71f57d6d3e0b3726ab473b8f4
|
4
|
+
data.tar.gz: 3171e12d387c900f3ee7e1892d45c51bc96ab11e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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
|
-
|
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.
|
26
|
-
to = reflection.klass.
|
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::
|
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
|
data/lib/track_changes/engine.rb
CHANGED
@@ -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
|
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
|
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/
|
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
|