culturecode-track_changes 0.0.1 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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