paper_trail 8.1.2 → 9.0.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.
Files changed (38) hide show
  1. checksums.yaml +4 -4
  2. data/lib/generators/paper_trail/install_generator.rb +2 -0
  3. data/lib/paper_trail.rb +130 -78
  4. data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +3 -1
  5. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +2 -0
  6. data/lib/paper_trail/attribute_serializers/object_attribute.rb +2 -0
  7. data/lib/paper_trail/attribute_serializers/object_changes_attribute.rb +2 -0
  8. data/lib/paper_trail/cleaner.rb +2 -0
  9. data/lib/paper_trail/config.rb +33 -8
  10. data/lib/paper_trail/frameworks/active_record.rb +2 -0
  11. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb +2 -0
  12. data/lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb +2 -0
  13. data/lib/paper_trail/frameworks/cucumber.rb +5 -3
  14. data/lib/paper_trail/frameworks/rails.rb +2 -0
  15. data/lib/paper_trail/frameworks/rails/controller.rb +28 -16
  16. data/lib/paper_trail/frameworks/rails/engine.rb +2 -0
  17. data/lib/paper_trail/frameworks/rspec.rb +5 -3
  18. data/lib/paper_trail/frameworks/rspec/helpers.rb +2 -0
  19. data/lib/paper_trail/has_paper_trail.rb +2 -1
  20. data/lib/paper_trail/model_config.rb +76 -14
  21. data/lib/paper_trail/queries/versions/where_object.rb +2 -0
  22. data/lib/paper_trail/queries/versions/where_object_changes.rb +3 -1
  23. data/lib/paper_trail/record_history.rb +2 -0
  24. data/lib/paper_trail/record_trail.rb +188 -48
  25. data/lib/paper_trail/reifier.rb +4 -2
  26. data/lib/paper_trail/reifiers/belongs_to.rb +2 -0
  27. data/lib/paper_trail/reifiers/has_and_belongs_to_many.rb +2 -0
  28. data/lib/paper_trail/reifiers/has_many.rb +2 -0
  29. data/lib/paper_trail/reifiers/has_many_through.rb +2 -0
  30. data/lib/paper_trail/reifiers/has_one.rb +52 -4
  31. data/lib/paper_trail/request.rb +183 -0
  32. data/lib/paper_trail/serializers/json.rb +2 -2
  33. data/lib/paper_trail/serializers/yaml.rb +10 -14
  34. data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +2 -0
  35. data/lib/paper_trail/version_association_concern.rb +1 -1
  36. data/lib/paper_trail/version_concern.rb +2 -6
  37. data/lib/paper_trail/version_number.rb +5 -3
  38. metadata +8 -21
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: a4d9e6729cf3633953e38a14daf62fbd663938de52a1d495cdcbc5b3b63a12c2
4
- data.tar.gz: c12f82f3b75a454cfd55b389923859fe799128430f6eb541fb93e10b2dd00454
3
+ metadata.gz: 24616bf1e1df70302e7417a24d60141dc2a0d20f1c6e8ac3690dbd4abf890a82
4
+ data.tar.gz: 8f0ea37c0b65a0c15bfbf4096db430e81d848952f6d42ecbc09d5028fa042d3e
5
5
  SHA512:
6
- metadata.gz: 14b592477bc7292c66c1791e0762e62b1a817ece28d44f5156f7c7242fb18e62b93ebbd92b0efd7172538184bae2aa0c9c914b59e3378b15b043748eefa1f340
7
- data.tar.gz: b5b5352145cbb72c796234d4761a69141de72cb0ecd74f914b7082e318ea868185cabfee3df3f91d7c0f5f7ccad23e2d4cb3495f89c26500d5dd390a03131f11
6
+ metadata.gz: 109af4466c2f6a61b42633bb94e46909203252757d7864250dd8e62cddfe82ef317419fc5ad8f784eecb453af387a02242b643b58b8eadd5778ce1e64c4b56a3
7
+ data.tar.gz: b840ca06183ff5411b0dcc493c8bdbc8abaa94060d8dfccaf1b0cbd0bbf69cd4bda4c2a98e3bd406d4760317e9949c89e306bd7b54e676237b162f3721f30497
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "rails/generators"
2
4
  require "rails/generators/active_record"
3
5
 
@@ -1,10 +1,26 @@
1
- require "active_support"
1
+ # frozen_string_literal: true
2
+
3
+ # AR does not require all of AS, but PT does. PT uses core_ext like
4
+ # `String#squish`, so we require `active_support/all`. Instead of eagerly
5
+ # loading all of AS here, we could put specific `require`s in only the various
6
+ # PT files that need them, but this seems easier to troubleshoot, though it may
7
+ # add a few milliseconds to rails boot time. If that becomes a pain point, we
8
+ # can revisit this decision.
9
+ require "active_support/all"
10
+
11
+ # AR is required for, eg. has_paper_trail.rb, so we could put this `require` in
12
+ # all of those files, but it seems easier to troubleshoot if we just make sure
13
+ # AR is loaded here before loading *any* of PT. See discussion of
14
+ # performance/simplicity tradeoff for activesupport above.
15
+ require "active_record"
16
+
2
17
  require "request_store"
3
18
  require "paper_trail/cleaner"
4
19
  require "paper_trail/config"
5
20
  require "paper_trail/has_paper_trail"
6
21
  require "paper_trail/record_history"
7
22
  require "paper_trail/reifier"
23
+ require "paper_trail/request"
8
24
  require "paper_trail/version_association_concern"
9
25
  require "paper_trail/version_concern"
10
26
  require "paper_trail/version_number"
@@ -31,124 +47,158 @@ module PaperTrail
31
47
  class << self
32
48
  # @api private
33
49
  def clear_transaction_id
34
- self.transaction_id = nil
50
+ ::ActiveSupport::Deprecation.warn(
51
+ "PaperTrail.clear_transaction_id is deprecated, " \
52
+ "use PaperTrail.request.clear_transaction_id",
53
+ caller(1)
54
+ )
55
+ request.clear_transaction_id
35
56
  end
36
57
 
37
- # Switches PaperTrail on or off.
58
+ # Switches PaperTrail on or off, for all threads.
38
59
  # @api public
39
60
  def enabled=(value)
40
61
  PaperTrail.config.enabled = value
41
62
  end
42
63
 
43
- # Returns `true` if PaperTrail is on, `false` otherwise.
44
- # PaperTrail is enabled by default.
64
+ # Returns `true` if PaperTrail is on, `false` otherwise. This is the
65
+ # on/off switch that affects all threads. Enabled by default.
45
66
  # @api public
46
67
  def enabled?
47
68
  !!PaperTrail.config.enabled
48
69
  end
49
70
 
50
- # Sets whether PaperTrail is enabled or disabled for the current request.
51
- # @api public
71
+ # @deprecated
52
72
  def enabled_for_controller=(value)
53
- paper_trail_store[:request_enabled_for_controller] = value
73
+ ::ActiveSupport::Deprecation.warn(
74
+ "PaperTrail.enabled_for_controller= is deprecated, " \
75
+ "use PaperTrail.request.enabled=",
76
+ caller(1)
77
+ )
78
+ request.enabled = value
54
79
  end
55
80
 
56
- # Returns `true` if PaperTrail is enabled for the request, `false` otherwise.
57
- #
58
- # See `PaperTrail::Rails::Controller#paper_trail_enabled_for_controller`.
59
- # @api public
81
+ # @deprecated
60
82
  def enabled_for_controller?
61
- !!paper_trail_store[:request_enabled_for_controller]
83
+ ::ActiveSupport::Deprecation.warn(
84
+ "PaperTrail.enabled_for_controller? is deprecated, " \
85
+ "use PaperTrail.request.enabled?",
86
+ caller(1)
87
+ )
88
+ request.enabled?
62
89
  end
63
90
 
64
- # Sets whether PaperTrail is enabled or disabled for this model in the
65
- # current request.
66
- # @api public
91
+ # @deprecated
67
92
  def enabled_for_model(model, value)
68
- paper_trail_store[:"enabled_for_#{model}"] = value
93
+ ::ActiveSupport::Deprecation.warn(
94
+ "PaperTrail.enabled_for_model is deprecated, " \
95
+ "use PaperTrail.request.enabled_for_model",
96
+ caller(1)
97
+ )
98
+ request.enabled_for_model(model, value)
69
99
  end
70
100
 
71
- # Returns `true` if PaperTrail is enabled for this model in the current
72
- # request, `false` otherwise.
73
- # @api public
101
+ # @deprecated
74
102
  def enabled_for_model?(model)
75
- !!paper_trail_store.fetch(:"enabled_for_#{model}", true)
103
+ ::ActiveSupport::Deprecation.warn(
104
+ "PaperTrail.enabled_for_model? is deprecated, " \
105
+ "use PaperTrail.request.enabled_for_model?",
106
+ caller(1)
107
+ )
108
+ request.enabled_for_model?(model)
76
109
  end
77
110
 
78
- # Returns a `::Gem::Version`, convenient for comparisons. This is
111
+ # Returns PaperTrail's `::Gem::Version`, convenient for comparisons. This is
79
112
  # recommended over `::PaperTrail::VERSION::STRING`.
80
113
  # @api public
81
114
  def gem_version
82
115
  ::Gem::Version.new(VERSION::STRING)
83
116
  end
84
117
 
118
+ # Set variables for the current request, eg. whodunnit.
119
+ #
120
+ # All request-level variables are now managed here, as of PT 9. Having the
121
+ # word "request" right there in your application code will remind you that
122
+ # these variables only affect the current request, not all threads.
123
+ #
124
+ # Given a block, temporarily sets the given `options` and execute the block.
125
+ #
126
+ # Without a block, this currently just returns `PaperTrail::Request`.
127
+ # However, please do not use `PaperTrail::Request` directly. Currently,
128
+ # `Request` is a `Module`, but in the future it is quite possible we may
129
+ # make it a `Class`. If we make such a choice, we will not provide any
130
+ # warning and will not treat it as a breaking change. You've been warned :)
131
+ #
132
+ # @api public
133
+ def request(options = nil, &block)
134
+ if options.nil? && !block_given?
135
+ Request
136
+ else
137
+ Request.with(options, &block)
138
+ nil
139
+ end
140
+ end
141
+
85
142
  # Set the field which records when a version was created.
86
143
  # @api public
87
144
  def timestamp_field=(_field_name)
88
145
  raise(E_TIMESTAMP_FIELD_CONFIG)
89
146
  end
90
147
 
91
- # Sets who is responsible for any changes that occur. You would normally use
92
- # this in a migration or on the console, when working with models directly.
93
- # In a controller it is set automatically to the `current_user`.
94
- # @api public
148
+ # @deprecated
95
149
  def whodunnit=(value)
96
- paper_trail_store[:whodunnit] = value
150
+ ::ActiveSupport::Deprecation.warn(
151
+ "PaperTrail.whodunnit= is deprecated, use PaperTrail.request.whodunnit=",
152
+ caller(1)
153
+ )
154
+ request.whodunnit = value
97
155
  end
98
156
 
99
- # If nothing passed, returns who is reponsible for any changes that occur.
100
- #
101
- # PaperTrail.whodunnit = "someone"
102
- # PaperTrail.whodunnit # => "someone"
103
- #
104
- # If value and block passed, set this value as whodunnit for the duration of the block
105
- #
106
- # PaperTrail.whodunnit("me") do
107
- # puts PaperTrail.whodunnit # => "me"
108
- # end
109
- #
110
- # @api public
111
- def whodunnit(value = nil)
112
- if value
113
- raise ArgumentError, "no block given" unless block_given?
114
-
115
- previous_whodunnit = paper_trail_store[:whodunnit]
116
- paper_trail_store[:whodunnit] = value
117
-
118
- begin
119
- yield
120
- ensure
121
- paper_trail_store[:whodunnit] = previous_whodunnit
122
- end
123
- elsif paper_trail_store[:whodunnit].respond_to?(:call)
124
- paper_trail_store[:whodunnit].call
157
+ # @deprecated
158
+ def whodunnit(value = nil, &block)
159
+ if value.nil?
160
+ ::ActiveSupport::Deprecation.warn(
161
+ "PaperTrail.whodunnit is deprecated, use PaperTrail.request.whodunnit",
162
+ caller(1)
163
+ )
164
+ request.whodunnit
165
+ elsif block_given?
166
+ ::ActiveSupport::Deprecation.warn(
167
+ "Passing a block to PaperTrail.whodunnit is deprecated, " \
168
+ 'use PaperTrail.request(whodunnit: "John") do .. end',
169
+ caller(1)
170
+ )
171
+ request(whodunnit: value, &block)
125
172
  else
126
- paper_trail_store[:whodunnit]
173
+ raise ArgumentError, "Invalid arguments"
127
174
  end
128
175
  end
129
176
 
130
- # Sets any information from the controller that you want PaperTrail to
131
- # store. By default this is set automatically by a before filter.
132
- # @api public
177
+ # @deprecated
133
178
  def controller_info=(value)
134
- paper_trail_store[:controller_info] = value
179
+ ::ActiveSupport::Deprecation.warn(
180
+ "PaperTrail.controller_info= is deprecated, use PaperTrail.request.controller_info=",
181
+ caller(1)
182
+ )
183
+ request.controller_info = value
135
184
  end
136
185
 
137
- # Returns any information from the controller that you want
138
- # PaperTrail to store.
139
- #
140
- # See `PaperTrail::Rails::Controller#info_for_paper_trail`.
141
- # @api public
186
+ # @deprecated
142
187
  def controller_info
143
- paper_trail_store[:controller_info]
188
+ ::ActiveSupport::Deprecation.warn(
189
+ "PaperTrail.controller_info is deprecated, use PaperTrail.request.controller_info",
190
+ caller(1)
191
+ )
192
+ request.controller_info
144
193
  end
145
194
 
146
- # Getter and Setter for PaperTrail Serializer
195
+ # Set the PaperTrail serializer. This setting affects all threads.
147
196
  # @api public
148
197
  def serializer=(value)
149
198
  PaperTrail.config.serializer = value
150
199
  end
151
200
 
201
+ # Get the PaperTrail serializer used by all threads.
152
202
  # @api public
153
203
  def serializer
154
204
  PaperTrail.config.serializer
@@ -156,27 +206,29 @@ module PaperTrail
156
206
 
157
207
  # @api public
158
208
  def transaction?
159
- ::ActiveRecord::Base.connection.open_transactions > 0
209
+ ::ActiveRecord::Base.connection.open_transactions.positive?
160
210
  end
161
211
 
162
- # @api public
212
+ # @deprecated
163
213
  def transaction_id
164
- paper_trail_store[:transaction_id]
214
+ ::ActiveSupport::Deprecation.warn(
215
+ "PaperTrail.transaction_id is deprecated without replacement.",
216
+ caller(1)
217
+ )
218
+ request.transaction_id
165
219
  end
166
220
 
167
- # @api public
221
+ # @deprecated
168
222
  def transaction_id=(id)
169
- paper_trail_store[:transaction_id] = id
170
- end
171
-
172
- # Thread-safe hash to hold PaperTrail's data. Initializing with needed
173
- # default values.
174
- # @api private
175
- def paper_trail_store
176
- RequestStore.store[:paper_trail] ||= { request_enabled_for_controller: true }
223
+ ::ActiveSupport::Deprecation.warn(
224
+ "PaperTrail.transaction_id= is deprecated without replacement.",
225
+ caller(1)
226
+ )
227
+ request.transaction_id = id
177
228
  end
178
229
 
179
- # Returns PaperTrail's configuration object.
230
+ # Returns PaperTrail's global configuration object, a singleton. These
231
+ # settings affect all threads.
180
232
  # @api private
181
233
  def config
182
234
  @config ||= PaperTrail::Config.instance
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paper_trail/type_serializers/postgres_array_serializer"
2
4
 
3
5
  module PaperTrail
@@ -7,7 +9,7 @@ module PaperTrail
7
9
  # replaces certain default Active Record serializers
8
10
  # with custom PaperTrail ones.
9
11
  module AttributeSerializerFactory
10
- AR_PG_ARRAY_CLASS = "ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array".freeze
12
+ AR_PG_ARRAY_CLASS = "ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array"
11
13
 
12
14
  def self.for(klass, attr)
13
15
  active_record_serializer = klass.type_for_attribute(attr)
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paper_trail/attribute_serializers/attribute_serializer_factory"
2
4
 
3
5
  module PaperTrail
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paper_trail/attribute_serializers/cast_attribute_serializer"
2
4
 
3
5
  module PaperTrail
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paper_trail/attribute_serializers/cast_attribute_serializer"
2
4
 
3
5
  module PaperTrail
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module PaperTrail
2
4
  # Utilities for deleting version records.
3
5
  module Cleaner
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "singleton"
2
4
  require "paper_trail/serializers/yaml"
3
5
 
@@ -5,9 +7,26 @@ module PaperTrail
5
7
  # Global configuration affecting all threads. Some thread-specific
6
8
  # configuration can be found in `paper_trail.rb`, others in `controller.rb`.
7
9
  class Config
10
+ DPR_TRACK_ASSOC = <<~STR
11
+ Association tracking is an endangered feature. For the past three or four
12
+ years it has been an experimental feature, not recommended for production.
13
+ It has a long list of known issues
14
+ (https://github.com/airblade/paper_trail#4b1-known-issues) and has no
15
+ regular volunteers caring for it.
16
+
17
+ If you don't use this feature, I strongly recommend disabling it.
18
+
19
+ If you do use this feature, please head over to
20
+ https://github.com/airblade/paper_trail/issues/1070 and volunteer to work
21
+ on the known issues.
22
+
23
+ If we can't make a serious dent in the list of known issues over the next
24
+ few years, then I'm inclined to delete it, though that would make me sad
25
+ because I've put dozens of hours into it, and I know others have too.
26
+ STR
27
+
8
28
  include Singleton
9
29
  attr_accessor :serializer, :version_limit
10
- attr_writer :track_associations
11
30
 
12
31
  def initialize
13
32
  # Variables which affect all threads, whose access is synchronized.
@@ -18,18 +37,24 @@ module PaperTrail
18
37
  @serializer = PaperTrail::Serializers::YAML
19
38
  end
20
39
 
21
- # Previously, we checked `PaperTrail::VersionAssociation.table_exists?`
40
+ def track_associations=(value)
41
+ @track_associations = !!value
42
+ if @track_associations
43
+ ::ActiveSupport::Deprecation.warn(DPR_TRACK_ASSOC, caller(1))
44
+ end
45
+ end
46
+
47
+ # As of PaperTrail 5, `track_associations?` defaults to false. Tracking
48
+ # associations is an experimental feature so we recommend setting
49
+ # PaperTrail.config.track_associations = false in your
50
+ # config/initializers/paper_trail.rb
51
+ #
52
+ # In PT 4, we checked `PaperTrail::VersionAssociation.table_exists?`
22
53
  # here, but that proved to be problematic in situations when the database
23
54
  # connection had not been established, or when the database does not exist
24
55
  # yet (as with `rake db:create`).
25
56
  def track_associations?
26
57
  if @track_associations.nil?
27
- ActiveSupport::Deprecation.warn <<-EOS.strip_heredoc.gsub(/\s+/, " ")
28
- PaperTrail.config.track_associations has not been set. As of PaperTrail 5, it
29
- defaults to false. Tracking associations is an experimental feature so
30
- we recommend setting PaperTrail.config.track_associations = false in
31
- your config/initializers/paper_trail.rb
32
- EOS
33
58
  false
34
59
  else
35
60
  @track_associations
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # This file only needs to be loaded if the gem is being used outside of Rails,
2
4
  # since otherwise the model(s) will get loaded in via the `Rails::Engine`.
3
5
  require "paper_trail/frameworks/active_record/models/paper_trail/version_association"
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paper_trail/version_concern"
2
4
 
3
5
  module PaperTrail
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require "paper_trail/version_association_concern"
2
4
 
3
5
  module PaperTrail
@@ -1,9 +1,11 @@
1
+ # frozen_string_literal: true
2
+
1
3
  # before hook for Cucumber
2
4
  Before do
3
5
  PaperTrail.enabled = false
4
- PaperTrail.enabled_for_controller = true
5
- PaperTrail.whodunnit = nil
6
- PaperTrail.controller_info = {} if defined? Rails
6
+ PaperTrail.request.enabled = true
7
+ PaperTrail.request.whodunnit = nil
8
+ PaperTrail.request.controller_info = {} if defined?(::Rails)
7
9
  end
8
10
 
9
11
  module PaperTrail