culturecode-track_changes 0.2.1 → 0.3.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
  SHA256:
3
- metadata.gz: 740a90693ee8263535857c6037b35d1f005a3ad3e9f6e1d200b8db1fefa82a89
4
- data.tar.gz: df7bbc71ddfd165f0cc2cb347284b6fcb4aa334b58699e24e7294a35d8a540e2
3
+ metadata.gz: 0c9bb5bdbc7a137501b16be9525858c58cd8665a673f0d81616e7ea08bda7c5b
4
+ data.tar.gz: 6b1b61340da3ca8e3af00f43cb8b4ed8fb634a03a5111301e9d30501258bccad
5
5
  SHA512:
6
- metadata.gz: c06836667b94b7a4a873662a4ac105d4d4ad190b325c91f978147231d4cf107187c3d446f2e9d8250cb4e1a243166e712fed9a3c713c3bfe0db374620092db6d
7
- data.tar.gz: 138ed42c7a8549ead7070afdc61fea6a0b00ea56745d2b3e906515eec785d81b73647a99eb0d5d80e608e3d0ebf9be404023caf4220d59b785609fcf1ae54587
6
+ metadata.gz: 458e536d0b57c406cc66b150b5be511a086aaf5b1fc6aad7e282d0aeb1d8bd4cfb1ce1296820ccfaf03098c25b6d38d6d8ddd4dbfce3195160c803666cd4b3da
7
+ data.tar.gz: da6901abda1bd01c87b01b0f7cc00be43226f0f7e29a1d480790542930d6a95e86d8a7d76b5a7c0d07839e79217d29a1eb9660318de29fbaf7f840775ec0d55f
data/README.md CHANGED
@@ -24,6 +24,13 @@ class CreateTrackChangesTables < ActiveRecord::Migration
24
24
  end
25
25
  ```
26
26
 
27
+ ## Configuration
28
+
29
+ ```ruby
30
+ TrackChanges::Configuration.cascade_destroy = false # Controls whether tracked changes are deleted when the record is deleted. Can be set to false if an audit trail of destroyed records is desired. Default: true
31
+ TrackChanges::Configuration.serialize = false # Controls whether tracked changes are serialized as YAML before being written to the database. Can be set to false if the `state`, `from`, and `to` columns are JSON datatype instead of text. Default: true
32
+ ```
33
+
27
34
  ## Usage
28
35
 
29
36
  ```ruby
@@ -32,6 +39,11 @@ class Person < ActiveRecord::Base
32
39
  end
33
40
  ```
34
41
 
42
+ ```ruby
43
+ Person.snapshot_all # Initialize snapshots for existing records so the next time the record is saved a diff can be generated.
44
+ Person.tracked_change(status: "approved", assigned_to: "user_123") # Returns a list of diffs where specific attributes changed to the specified values.
45
+ ```
46
+
35
47
  ### Options
36
48
  By default all model attributes are tracked, except the primary_key, usually ```id```, ```created_at```, and ```updated_at```.
37
49
 
@@ -29,13 +29,14 @@ module TrackChanges
29
29
 
30
30
  if record = diff.record
31
31
  field_name = diff.record.class.human_attribute_name(field)
32
- reflection = diff.record.class.reflections.values.detect {|reflection| reflection.foreign_key == field.to_s }
32
+ reflection = diff.record.class.reflect_on_association(field) # Look up association by name, e.g. users for has_many :users
33
+ reflection ||= diff.record.class.reflections.values.detect {|ref| ref.foreign_key == field.to_s } # Detect association by foreign key, e.g. user_id for belongs_to :user
33
34
  end
34
35
 
35
36
  if reflection
36
37
  primary_key = reflection.options.fetch(:primary_key, :id)
37
- from = reflection.klass.find_by(primary_key => from) || content_tag(:span, 'DELETED', :class => 'deleted', :title => "This #{field_name} has been deleted") if from.present?
38
- to = reflection.klass.find_by(primary_key => to) || content_tag(:span, 'DELETED', :class => 'deleted', :title => "This #{field_name} has been deleted") if to.present?
38
+ from = reflection.klass.where(primary_key => from) || content_tag(:span, 'DELETED', :class => 'deleted', :title => "This #{field_name} has been deleted") if from.present?
39
+ to = reflection.klass.where(primary_key => to) || content_tag(:span, 'DELETED', :class => 'deleted', :title => "This #{field_name} has been deleted") if to.present?
39
40
  end
40
41
 
41
42
  if from.blank?
@@ -49,8 +50,8 @@ module TrackChanges
49
50
 
50
51
  def link_diff_field_value(value, link_models = [])
51
52
  case value
52
- when Array
53
- value.collect{|v| link_diff_field_value(v, link_models) }.to_sentence.html_safe
53
+ when Array, ActiveRecord::Relation
54
+ safe_join(value.collect {|v| link_diff_field_value(v, link_models) }, ', ')
54
55
  when *link_models
55
56
  link_to(value.to_s, value)
56
57
  else
@@ -4,8 +4,10 @@ module TrackChanges
4
4
 
5
5
  belongs_to :record, :polymorphic => true
6
6
 
7
- serialize :from, Hash
8
- serialize :to, Hash
7
+ if Configuration.serialize
8
+ serialize :from, Hash
9
+ serialize :to, Hash
10
+ end
9
11
 
10
12
  # Returns changes but only those where the string representation of the value has changed
11
13
  def visible_changes
@@ -4,13 +4,26 @@ module TrackChanges
4
4
 
5
5
  belongs_to :record, :polymorphic => true
6
6
 
7
- serialize :state, Hash
7
+ serialize :state, Hash if Configuration.serialize
8
8
 
9
9
  before_save :capture_record_state
10
10
 
11
11
  # Returns a hash of the current values for all tracked fields on the record
12
12
  def self.record_state(record)
13
- Hash[record.class.track_changes_fields.collect {|method_name| [method_name, record.send(method_name)] }]
13
+ Hash[record.class.track_changes_fields.collect {|method_name| [method_name, dump_attribute_value(record.send(method_name))] }]
14
+ end
15
+
16
+ def self.dump_attribute_value(value)
17
+ case value
18
+ when ActiveRecord::Relation
19
+ dump_attribute_value(value.to_a).sort
20
+ when Array
21
+ value.map {|member| dump_attribute_value(member) }
22
+ when ActiveRecord::Base
23
+ value.send(value.class.primary_key)
24
+ else
25
+ value
26
+ end
14
27
  end
15
28
 
16
29
  # Creates a diff object that shows the changes between this snapshot and the record's state
@@ -21,7 +34,7 @@ module TrackChanges
21
34
  to = {}
22
35
 
23
36
  record.class.track_changes_fields.each do |key|
24
- if snapshot_state.key?(key) && snapshot_state[key] != record_state[key]
37
+ if snapshot_state.key?(key) && snapshot_state[key] != record_state[key] # We check for the existence of the key in the snapshot before recording so we don't declare newly tracked attributes as "changed" on their first time recorded
25
38
  from[key] = snapshot_state[key]
26
39
  to[key] = record_state[key]
27
40
  end
@@ -1,6 +1,6 @@
1
1
  module TrackChanges
2
- module Configuration
3
- mattr_accessor :cascade_destroy # Destroy tracked changes when record is destroyed?
4
- self.cascade_destroy = true
2
+ module Configuration
3
+ mattr_accessor :cascade_destroy, :default => true # Destroy tracked changes when record is destroyed?
4
+ mattr_accessor :serialize, :default => true # Serialize data in ruby before writing to the database. Not necessary if the diff and snapshot data columns are JSON.
5
5
  end
6
6
  end
@@ -90,6 +90,27 @@ module TrackChanges
90
90
  new_record?
91
91
  end
92
92
  end
93
+
94
+ # Filters tracked change diffs to only those where the given attributes changed *to* the specified values.
95
+ #
96
+ # It builds a scope that matches records where each given attribute in `to` has the specified value.
97
+ #
98
+ # Example:
99
+ # model.tracked_change(status: "approved", priority: "high")
100
+ # # => returns diffs where status became "approved" and priority became "high"
101
+ #
102
+ # Params:
103
+ # - changes (keyword arguments): One or more attribute-value pairs to match against the `to` column.
104
+ #
105
+ # Returns:
106
+ # - ActiveRecord::Relation: A filtered scope on the diffs table.
107
+ def tracked_change(**changes)
108
+ table_name = diffs.quoted_table_name
109
+ column_name = diffs.connection.quote_column_name(:to)
110
+ changes.reduce(diffs) do |scope, (attribute, value)|
111
+ scope.where("#{table_name}.#{column_name} ->> ? = ?", attribute, value)
112
+ end
113
+ end
93
114
  end
94
115
  end
95
116
  end
@@ -1,3 +1,3 @@
1
1
  module TrackChanges
2
- VERSION = "0.2.1"
2
+ VERSION = "0.3.0"
3
3
  end
metadata CHANGED
@@ -1,14 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: culturecode-track_changes
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Jakobsen, Ryan Wallace
8
- autorequire:
9
8
  bindir: bin
10
9
  cert_chain: []
11
- date: 2023-08-22 00:00:00.000000000 Z
10
+ date: 1980-01-02 00:00:00.000000000 Z
12
11
  dependencies:
13
12
  - !ruby/object:Gem::Dependency
14
13
  name: rails
@@ -65,7 +64,6 @@ homepage: https://github.com/culturecode/track_changes
65
64
  licenses:
66
65
  - MIT
67
66
  metadata: {}
68
- post_install_message:
69
67
  rdoc_options: []
70
68
  require_paths:
71
69
  - lib
@@ -80,8 +78,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
80
78
  - !ruby/object:Gem::Version
81
79
  version: '0'
82
80
  requirements: []
83
- rubygems_version: 3.3.23
84
- signing_key:
81
+ rubygems_version: 3.6.9
85
82
  specification_version: 4
86
83
  summary: Easily track changes to various ActiveRecord models
87
84
  test_files: []