paper_trail_scrapbook 0.1.13 → 0.1.15

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: 6c453ce85bdc41cc81c5f1d9f16922ae23c3936d
4
- data.tar.gz: dc47a13264e5bb62434b4e8cd169c78e607b7842
3
+ metadata.gz: 3cd11a4eeaf7c668fe41fe854748cf0f2e8fcaed
4
+ data.tar.gz: a1143aad24dcaa956b19fd47142e7e52b52bc8c4
5
5
  SHA512:
6
- metadata.gz: 1848ed2409a099393b9adf26975d2b35575f742fe18b4d9a8af22108739102ab58aa663b9c28f68f38b7f16a9f007d4c1c759071fcb7b49d9126817d47f23d79
7
- data.tar.gz: 7d9e1dbbf17832aa1e95b82f97efbf4d70d2596f4652b9d88256a56a2fcdb573b5a000236e333522193262681931ee34b8333f060d9be5c1fa143f7e15f265b9
6
+ metadata.gz: 7d8ef81dbaa77a0a90944adc34086ef4482fa6a97304490f4f929520465e7b56398868beb04f0ad433742b2d94fed78d019b63a36603ccd62d08ecba4b022c6a
7
+ data.tar.gz: ff4accb4de852aaacff14195e42b520ee4eac4f3a95370d8e43d24e1aa7492c3afd752af0e68524757438a14cb5383c1f8f256713bfb20c9d51ab8cc6a5962e4
data/Gemfile.lock CHANGED
@@ -1,11 +1,11 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- paper_trail_scrapbook (0.1.13)
4
+ paper_trail_scrapbook (0.1.15)
5
5
  activerecord
6
6
  adamantium
7
7
  concord
8
- paper_trail (>= 5.2, <= 9.2.0)
8
+ paper_trail (>= 5.2, <= 10.2.1)
9
9
 
10
10
  GEM
11
11
  remote: https://rubygems.org/
@@ -100,11 +100,9 @@ GEM
100
100
  rspec-core (>= 3.4.0, < 3.7.0)
101
101
  nokogiri (1.10.2)
102
102
  mini_portile2 (~> 2.4.0)
103
- paper_trail (9.2.0)
104
- activerecord (>= 4.2, < 5.3)
105
- paper_trail-association_tracking (< 2)
103
+ paper_trail (10.2.1)
104
+ activerecord (>= 4.2, < 6.1)
106
105
  request_store (~> 1.1)
107
- paper_trail-association_tracking (1.1.1)
108
106
  parallel (1.12.1)
109
107
  parser (2.4.0.2)
110
108
  ast (~> 2.3)
data/README.md CHANGED
@@ -60,6 +60,14 @@ end
60
60
  PaperTrailScrapbook.config.whodunnit_class = WhoDidIt
61
61
  ```
62
62
 
63
+ You also have the option of seeing the most recent changes first (default is chronological)
64
+
65
+ ```ruby
66
+
67
+ config.recent_first = true
68
+
69
+ ```
70
+
63
71
  ### Life Story
64
72
 
65
73
  The `LifeStory` module provides a complete history of an object (limited by the
@@ -8,6 +8,11 @@ module PaperTrailScrapbook
8
8
  class Changes
9
9
  include Concord.new(:version)
10
10
  include Adamantium::Flat
11
+ include PaperTrailScrapbook::VersionHelpers
12
+
13
+ POLYMORPH_BT_INDICATOR = '*'
14
+
15
+ delegate :object_changes, to: :version
11
16
 
12
17
  def initialize(*)
13
18
  super
@@ -23,10 +28,11 @@ module PaperTrailScrapbook
23
28
  # @return [String] Summary analysis of changes
24
29
  #
25
30
  def change_log
26
- text = changes
27
- .map { |k, v| digest(k, v) }
28
- .compact
29
- .join("\n")
31
+ text =
32
+ changes
33
+ .map { |k, v| digest(k, v) }
34
+ .compact
35
+ .join("\n")
30
36
 
31
37
  text = text.gsub(' id:', ':') if PaperTrailScrapbook.config.drop_id_suffix
32
38
  text
@@ -34,9 +40,13 @@ module PaperTrailScrapbook
34
40
 
35
41
  private
36
42
 
43
+ def polymorphic?(x)
44
+ x.to_s.start_with?(POLYMORPH_BT_INDICATOR)
45
+ end
46
+
37
47
  def digest(key, values)
38
48
  old, new = values
39
- return if old.nil? && (new.nil? || new.eql?('')) || (old == new)
49
+ return if old.nil? && (new.nil? || new.eql?('')) || (old == new && !creating?)
40
50
 
41
51
  "#{BULLET} #{key.tr('_', ' ')}: #{detailed_analysis(key, new, old)}"
42
52
  end
@@ -63,17 +73,40 @@ module PaperTrailScrapbook
63
73
  return '*empty*' unless value
64
74
 
65
75
  begin
66
- build_associations[key].find(value).to_s.to_s + "[#{value}]"
76
+ assoc_target(key).find(value).to_s.to_s + "[#{value}]"
67
77
  rescue StandardError
68
78
  "*not found*[#{value}]"
69
79
  end
70
80
  end
71
81
 
82
+ def assoc_target(key)
83
+ x = build_associations[key]
84
+ return x unless polymorphic?(x)
85
+ ref = x[1..-1] + '_type'
86
+
87
+ # try object changes to see if the belongs_to class is specified
88
+ latest_class = changes[ref]&.last
89
+
90
+ if latest_class.nil? && create?
91
+ # try the db default class
92
+ # for creates where the object changes do not specify this it
93
+ # is most likely because the default == type selected so
94
+ # the default was not changed and therefore is not in
95
+ # object changes
96
+ orig_instance = Object.const_get(version.item_type.classify).new
97
+ latest_class = orig_instance[ref.to_sym]
98
+ end
99
+
100
+ Object.const_get(latest_class.classify)
101
+ end
102
+
72
103
  def assoc_klass(name, options = {})
73
104
  direct_class = options[:class_name]
74
- return direct_class if direct_class && !direct_class.is_a?(String)
105
+ poly = options[:polymorphic]
106
+
107
+ return direct_class if !poly && direct_class && !direct_class.is_a?(String)
75
108
 
76
- Object.const_get((direct_class || name.to_s).classify)
109
+ poly ? POLYMORPH_BT_INDICATOR + name.to_s : Object.const_get((direct_class || name.to_s).classify)
77
110
  rescue StandardError
78
111
  Object.const_set(name.to_s.classify, Class.new)
79
112
  end
@@ -86,16 +119,12 @@ module PaperTrailScrapbook
86
119
  @build_associations ||=
87
120
  Hash[
88
121
  klass
89
- .reflect_on_all_associations
90
- .select { |a| a.macro.equal?(:belongs_to) }
91
- .map { |x| [x.foreign_key.to_s, assoc_klass(x.name, x.options)] }
122
+ .reflect_on_all_associations
123
+ .select { |a| a.macro.equal?(:belongs_to) }
124
+ .map { |x| [x.foreign_key.to_s, assoc_klass(x.name, x.options)] }
92
125
  ]
93
126
  end
94
127
 
95
- def object_changes
96
- version.object_changes
97
- end
98
-
99
128
  def changes
100
129
  @changes ||= if object_changes
101
130
  YAML
@@ -22,7 +22,8 @@ module PaperTrailScrapbook
22
22
  :drop_id_suffix,
23
23
  :unknown_whodunnit,
24
24
  :invalid_whodunnit,
25
- :filter_non_changes
25
+ :filter_non_changes,
26
+ :recent_first
26
27
 
27
28
  def initialize
28
29
  @whodunnit_class = nil
@@ -33,6 +34,7 @@ module PaperTrailScrapbook
33
34
  @invalid_whodunnit = proc { |w| "*missing (#{w})*" }
34
35
  @drop_id_suffix = true
35
36
  @filter_non_changes = true
37
+ @recent_first = false
36
38
  end
37
39
  end
38
40
  end
@@ -23,13 +23,17 @@ module PaperTrailScrapbook
23
23
  # @return [String] analyzed versions
24
24
  #
25
25
  def story
26
- versions.map do |v|
26
+ x = versions.map do |v|
27
27
  if primary?(v)
28
28
  Chapter
29
29
  else
30
30
  SecondaryChapter
31
31
  end.new(v).story
32
- end.compact.join("\n\n")
32
+ end.compact
33
+
34
+ x.reverse! if PaperTrailScrapbook.config.recent_first
35
+
36
+ x.join("\n\n")
33
37
  end
34
38
 
35
39
  private
@@ -26,7 +26,11 @@ module PaperTrailScrapbook
26
26
  def story
27
27
  s = versions.map do |v|
28
28
  JournalEntry.new(v).story
29
- end.compact.join("\n\n")
29
+ end.compact
30
+
31
+ s.reverse! if PaperTrailScrapbook.config.recent_first
32
+
33
+ s.join("\n\n")
30
34
 
31
35
  "#{preface}#{s.presence || 'No history'}"
32
36
  end
@@ -2,5 +2,5 @@
2
2
 
3
3
  module PaperTrailScrapbook
4
4
  # Current version
5
- VERSION = '0.1.13'
5
+ VERSION = '0.1.15'
6
6
  end
@@ -21,7 +21,7 @@ Gem::Specification.new do |gem|
21
21
  gem.add_dependency 'activerecord'
22
22
  gem.add_dependency 'adamantium'
23
23
  gem.add_dependency 'concord'
24
- gem.add_dependency 'paper_trail', ['>= 5.2', '<= 9.2.0']
24
+ gem.add_dependency 'paper_trail', ['>= 5.2', '<= 10.2.1']
25
25
 
26
26
  gem.add_development_dependency 'ffaker', '~> 2.5'
27
27
  gem.add_development_dependency 'rake', '~> 10.4.2'
@@ -5,7 +5,7 @@ require 'securerandom'
5
5
  class CustomPrimaryKeyRecord < ActiveRecord::Base
6
6
  self.primary_key = :uuid
7
7
 
8
- has_paper_trail class_name: 'CustomPrimaryKeyRecordVersion'
8
+ has_paper_trail versions: { class_name: 'CustomPrimaryKeyRecordVersion' }
9
9
 
10
10
  # This default_scope is to test the case of the Version#item association
11
11
  # not returning the item due to unmatched default_scope on the model.
@@ -2,7 +2,7 @@
2
2
 
3
3
  class Document < ActiveRecord::Base
4
4
  has_paper_trail(
5
- versions: :paper_trail_versions,
5
+ versions: {name: :paper_trail_versions},
6
6
  on: %i[create update]
7
7
  )
8
8
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module Kitchen
4
4
  class Banana < ActiveRecord::Base
5
- has_paper_trail class_name: 'Kitchen::BananaVersion'
5
+ has_paper_trail versions: { class_name: 'Kitchen::BananaVersion' }
6
6
  end
7
7
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Post < ActiveRecord::Base
4
- has_paper_trail class_name: 'PostVersion'
4
+ has_paper_trail versions: { class_name: 'PostVersion' }
5
5
  end
@@ -1,3 +1 @@
1
1
  # frozen_string_literal: true
2
-
3
- PaperTrail.config.track_associations = false
@@ -61,7 +61,7 @@ module PaperTrailScrapbook
61
61
  .to match(/How the Grinch stole Xmas\[\d+\] was \*removed\*/)
62
62
  end
63
63
 
64
- context 'it handles missing whodunnit record' do
64
+ context 'when it handles missing whodunnit record' do
65
65
  it 'provides a whole story with missing whodunnit record' do
66
66
  target
67
67
  pid = person.id
@@ -88,7 +88,7 @@ module PaperTrailScrapbook
88
88
  end
89
89
  end
90
90
 
91
- context 'no papertrail' do
91
+ context 'without papertrail' do
92
92
  let(:target) { Elephant.create! }
93
93
 
94
94
  it 'has none' do
@@ -97,6 +97,15 @@ module PaperTrailScrapbook
97
97
  end
98
98
  end
99
99
 
100
+ context 'with polymorphic data' do
101
+ let(:target) { Whatchamajigger.create!(owner: author) }
102
+
103
+ it 'locates the proper model' do
104
+ expect(subject).to match(/Dr. Seuss\[/)
105
+ expect(subject).to match(/owner type: Person/)
106
+ end
107
+ end
108
+
100
109
  context 'with related data' do
101
110
  before do
102
111
  author
@@ -120,6 +129,42 @@ module PaperTrailScrapbook
120
129
  expect(subject).to match(/author: Dr\. Seuss\[\d+\]/)
121
130
  end
122
131
  end
132
+
133
+ context 'recent first' do
134
+ before do
135
+ author
136
+ book
137
+ target
138
+
139
+ config = PaperTrailScrapbook.config
140
+ config.recent_first = true
141
+ config.time_format = '%A, %d %b %Y at %l:%M:%S.%9N %p'
142
+
143
+ def target.trailed_related_content
144
+ [book, author]
145
+ end
146
+ end
147
+
148
+ after do
149
+ config = PaperTrailScrapbook.config
150
+ config.recent_first = false
151
+ config.time_format = '%A, %d %b %Y at %l:%M %p'
152
+ end
153
+
154
+ it 'includes related content history' do
155
+ expect(subject).to match(/created the following Person\[\d+\] info/)
156
+ expect(subject).to match(/name: Dr\. Seuss/)
157
+
158
+ expect(subject).to match(/created the following Book\[\d+\] info/)
159
+ expect(subject).to match(/title: How the Grinch stole Xmas/)
160
+
161
+ expect(subject.squish).to match(/created the following Book.*created the following Person/)
162
+
163
+ expect(subject).to match(/created the following Authorship info/)
164
+ expect(subject).to match(/book: How the Grinch stole Xmas\[\d+\]/)
165
+ expect(subject).to match(/author: Dr\. Seuss\[\d+\]/)
166
+ end
167
+ end
123
168
  end
124
169
  end
125
170
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paper_trail_scrapbook
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.13
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Timothy Chambers
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2019-03-28 00:00:00.000000000 Z
11
+ date: 2019-04-01 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -61,7 +61,7 @@ dependencies:
61
61
  version: '5.2'
62
62
  - - "<="
63
63
  - !ruby/object:Gem::Version
64
- version: 9.2.0
64
+ version: 10.2.1
65
65
  type: :runtime
66
66
  prerelease: false
67
67
  version_requirements: !ruby/object:Gem::Requirement
@@ -71,7 +71,7 @@ dependencies:
71
71
  version: '5.2'
72
72
  - - "<="
73
73
  - !ruby/object:Gem::Version
74
- version: 9.2.0
74
+ version: 10.2.1
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: ffaker
77
77
  requirement: !ruby/object:Gem::Requirement