paper_trail 8.1.2 → 9.0.0

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