paper_trail 9.2.0 → 12.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE +20 -0
  3. data/lib/generators/paper_trail/install/USAGE +3 -0
  4. data/lib/generators/paper_trail/{install_generator.rb → install/install_generator.rb} +15 -38
  5. data/lib/generators/paper_trail/{templates → install/templates}/add_object_changes_to_versions.rb.erb +0 -0
  6. data/lib/generators/paper_trail/{templates → install/templates}/create_versions.rb.erb +2 -2
  7. data/lib/generators/paper_trail/migration_generator.rb +38 -0
  8. data/lib/generators/paper_trail/update_item_subtype/USAGE +4 -0
  9. data/lib/generators/paper_trail/update_item_subtype/templates/update_versions_for_item_subtype.rb.erb +85 -0
  10. data/lib/generators/paper_trail/update_item_subtype/update_item_subtype_generator.rb +19 -0
  11. data/lib/paper_trail/attribute_serializers/attribute_serializer_factory.rb +24 -10
  12. data/lib/paper_trail/attribute_serializers/cast_attribute_serializer.rb +8 -46
  13. data/lib/paper_trail/compatibility.rb +51 -0
  14. data/lib/paper_trail/config.rb +9 -2
  15. data/lib/paper_trail/errors.rb +33 -0
  16. data/lib/paper_trail/events/base.rb +305 -0
  17. data/lib/paper_trail/events/create.rb +32 -0
  18. data/lib/paper_trail/events/destroy.rb +42 -0
  19. data/lib/paper_trail/events/update.rb +60 -0
  20. data/lib/paper_trail/frameworks/active_record.rb +9 -2
  21. data/lib/paper_trail/frameworks/rails/controller.rb +1 -9
  22. data/lib/paper_trail/frameworks/rails/railtie.rb +30 -0
  23. data/lib/paper_trail/frameworks/rails.rb +1 -2
  24. data/lib/paper_trail/has_paper_trail.rb +20 -17
  25. data/lib/paper_trail/model_config.rb +103 -71
  26. data/lib/paper_trail/queries/versions/where_attribute_changes.rb +50 -0
  27. data/lib/paper_trail/queries/versions/where_object.rb +4 -1
  28. data/lib/paper_trail/queries/versions/where_object_changes.rb +8 -13
  29. data/lib/paper_trail/queries/versions/where_object_changes_from.rb +57 -0
  30. data/lib/paper_trail/queries/versions/where_object_changes_to.rb +57 -0
  31. data/lib/paper_trail/record_trail.rb +94 -411
  32. data/lib/paper_trail/reifier.rb +41 -25
  33. data/lib/paper_trail/request.rb +0 -3
  34. data/lib/paper_trail/serializers/json.rb +0 -10
  35. data/lib/paper_trail/serializers/yaml.rb +5 -12
  36. data/lib/paper_trail/type_serializers/postgres_array_serializer.rb +1 -15
  37. data/lib/paper_trail/version_concern.rb +141 -61
  38. data/lib/paper_trail/version_number.rb +2 -2
  39. data/lib/paper_trail.rb +16 -123
  40. metadata +159 -56
  41. data/lib/generators/paper_trail/USAGE +0 -2
  42. data/lib/paper_trail/frameworks/rails/engine.rb +0 -14
@@ -52,26 +52,29 @@ module PaperTrail
52
52
  # not the actual subclass. If `type` is present but empty, the class is
53
53
  # the base class.
54
54
  def init_model(attrs, options, version)
55
- if options[:dup] != true && version.item
56
- model = version.item
57
- if options[:unversioned_attributes] == :nil
58
- init_unversioned_attrs(attrs, model)
59
- end
60
- else
61
- klass = version_reification_class(version, attrs)
62
- # The `dup` option always returns a new object, otherwise we should
63
- # attempt to look for the item outside of default scope(s).
64
- find_cond = { klass.primary_key => version.item_id }
65
- if options[:dup] || (item_found = klass.unscoped.where(find_cond).first).nil?
66
- model = klass.new
67
- elsif options[:unversioned_attributes] == :nil
68
- model = item_found
69
- init_unversioned_attrs(attrs, model)
70
- end
55
+ klass = version_reification_class(version, attrs)
56
+
57
+ # The `dup` option and destroyed version always returns a new object,
58
+ # otherwise we should attempt to load item or to look for the item
59
+ # outside of default scope(s).
60
+ model = if options[:dup] == true || version.event == "destroy"
61
+ klass.new
62
+ else
63
+ version.item || init_model_by_finding_item_id(klass, version) || klass.new
64
+ end
65
+
66
+ if options[:unversioned_attributes] == :nil && !model.new_record?
67
+ init_unversioned_attrs(attrs, model)
71
68
  end
69
+
72
70
  model
73
71
  end
74
72
 
73
+ # @api private
74
+ def init_model_by_finding_item_id(klass, version)
75
+ klass.unscoped.where(klass.primary_key => version.item_id).first
76
+ end
77
+
75
78
  # Look for attributes that exist in `model` and not in this version.
76
79
  # These attributes should be set to nil. Modifies `attrs`.
77
80
  # @api private
@@ -88,9 +91,7 @@ module PaperTrail
88
91
  #
89
92
  # @api private
90
93
  def reify_attribute(k, v, model, version)
91
- enums = model.class.respond_to?(:defined_enums) ? model.class.defined_enums : {}
92
- is_enum_without_type_caster = ::ActiveRecord::VERSION::MAJOR < 5 && enums.key?(k)
93
- if model.has_attribute?(k) && !is_enum_without_type_caster
94
+ if model.has_attribute?(k)
94
95
  model[k.to_sym] = v
95
96
  elsif model.respond_to?("#{k}=")
96
97
  model.send("#{k}=", v)
@@ -111,20 +112,35 @@ module PaperTrail
111
112
  end
112
113
 
113
114
  # Given a `version`, return the class to reify. This method supports
114
- # Single Table Inheritance (STI) with custom inheritance columns.
115
+ # Single Table Inheritance (STI) with custom inheritance columns and
116
+ # custom inheritance column values.
115
117
  #
116
118
  # For example, imagine a `version` whose `item_type` is "Animal". The
117
119
  # `animals` table is an STI table (it has cats and dogs) and it has a
118
120
  # custom inheritance column, `species`. If `attrs["species"]` is "Dog",
119
121
  # this method returns the constant `Dog`. If `attrs["species"]` is blank,
120
- # this method returns the constant `Animal`. You can see this particular
121
- # example in action in `spec/models/animal_spec.rb`.
122
+ # this method returns the constant `Animal`.
123
+ #
124
+ # The values contained in the inheritance columns may be non-camelized
125
+ # strings (e.g. 'dog' instead of 'Dog'). To reify classes in this case
126
+ # we need to call the parents class `sti_class_for` method to retrieve
127
+ # the correct record class.
122
128
  #
129
+ # You can see these particular examples in action in
130
+ # `spec/models/animal_spec.rb` and `spec/models/plant_spec.rb`
123
131
  def version_reification_class(version, attrs)
124
- inheritance_column_name = version.item_type.constantize.inheritance_column
132
+ clazz = version.item_type.constantize
133
+ inheritance_column_name = clazz.inheritance_column
125
134
  inher_col_value = attrs[inheritance_column_name]
126
- class_name = inher_col_value.blank? ? version.item_type : inher_col_value
127
- class_name.constantize
135
+ return clazz if inher_col_value.blank?
136
+
137
+ # Rails 6.1 adds a public method for clients to use to customize STI classes. If that
138
+ # method is not available, fall back to using the private one
139
+ if clazz.public_methods.include?(:sti_class_for)
140
+ return clazz.sti_class_for(inher_col_value)
141
+ end
142
+
143
+ clazz.send(:find_sti_class, inher_col_value)
128
144
  end
129
145
  end
130
146
  end
@@ -12,9 +12,6 @@ module PaperTrail
12
12
  #
13
13
  # @api private
14
14
  module Request
15
- class InvalidOption < RuntimeError
16
- end
17
-
18
15
  class << self
19
16
  # Sets any data from the controller that you want PaperTrail to store.
20
17
  # See also `PaperTrail::Rails::Controller#info_for_paper_trail`.
@@ -31,16 +31,6 @@ module PaperTrail
31
31
  arel_field.matches("%\"#{field}\":#{json_value}%")
32
32
  end
33
33
  end
34
-
35
- def where_object_changes_condition(*)
36
- raise <<-STR.squish.freeze
37
- where_object_changes no longer supports reading JSON from a text
38
- column. The old implementation was inaccurate, returning more records
39
- than you wanted. This feature was deprecated in 7.1.0 and removed in
40
- 8.0.0. The json and jsonb datatypes are still supported. See the
41
- discussion at https://github.com/paper-trail-gem/paper_trail/issues/803
42
- STR
43
- end
44
34
  end
45
35
  end
46
36
  end
@@ -12,7 +12,12 @@ module PaperTrail
12
12
  ::YAML.load string
13
13
  end
14
14
 
15
+ # @param object (Hash | HashWithIndifferentAccess) - Coming from
16
+ # `recordable_object` `object` will be a plain `Hash`. However, due to
17
+ # recent [memory optimizations](https://git.io/fjeYv), when coming from
18
+ # `recordable_object_changes`, it will be a `HashWithIndifferentAccess`.
15
19
  def dump(object)
20
+ object = object.to_hash if object.is_a?(HashWithIndifferentAccess)
16
21
  ::YAML.dump object
17
22
  end
18
23
 
@@ -21,18 +26,6 @@ module PaperTrail
21
26
  def where_object_condition(arel_field, field, value)
22
27
  arel_field.matches("%\n#{field}: #{value}\n%")
23
28
  end
24
-
25
- # Returns a SQL LIKE condition to be used to match the given field and
26
- # value in the serialized `object_changes`.
27
- def where_object_changes_condition(*)
28
- raise <<-STR.squish.freeze
29
- where_object_changes no longer supports reading YAML from a text
30
- column. The old implementation was inaccurate, returning more records
31
- than you wanted. This feature was deprecated in 8.1.0 and removed in
32
- 9.0.0. The json and jsonb datatypes are still supported. See
33
- discussion at https://github.com/paper-trail-gem/paper_trail/pull/997
34
- STR
35
- end
36
29
  end
37
30
  end
38
31
  end
@@ -11,15 +11,12 @@ module PaperTrail
11
11
  end
12
12
 
13
13
  def serialize(array)
14
- return serialize_with_ar(array) if active_record_pre_502?
15
14
  array
16
15
  end
17
16
 
18
17
  def deserialize(array)
19
- return deserialize_with_ar(array) if active_record_pre_502?
20
-
21
18
  case array
22
- # Needed for legacy reasons. If serialized array is a string
19
+ # Needed for legacy data. If serialized array is a string
23
20
  # then it was serialized with Rails < 5.0.2.
24
21
  when ::String then deserialize_with_ar(array)
25
22
  else array
@@ -28,17 +25,6 @@ module PaperTrail
28
25
 
29
26
  private
30
27
 
31
- def active_record_pre_502?
32
- ::ActiveRecord::VERSION::MAJOR < 5 ||
33
- (::ActiveRecord::VERSION::MINOR.zero? && ::ActiveRecord::VERSION::TINY < 2)
34
- end
35
-
36
- def serialize_with_ar(array)
37
- ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.
38
- new(@subtype, @delimiter).
39
- serialize(array)
40
- end
41
-
42
28
  def deserialize_with_ar(array)
43
29
  ActiveRecord::ConnectionAdapters::PostgreSQL::OID::Array.
44
30
  new(@subtype, @delimiter).
@@ -1,8 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "paper_trail/attribute_serializers/object_changes_attribute"
4
+ require "paper_trail/queries/versions/where_attribute_changes"
4
5
  require "paper_trail/queries/versions/where_object"
5
6
  require "paper_trail/queries/versions/where_object_changes"
7
+ require "paper_trail/queries/versions/where_object_changes_from"
8
+ require "paper_trail/queries/versions/where_object_changes_to"
6
9
 
7
10
  module PaperTrail
8
11
  # Originally, PaperTrail did not provide this module, and all of this
@@ -13,12 +16,7 @@ module PaperTrail
13
16
  extend ::ActiveSupport::Concern
14
17
 
15
18
  included do
16
- if ::ActiveRecord.gem_version >= Gem::Version.new("5.0")
17
- belongs_to :item, polymorphic: true, optional: true
18
- else
19
- belongs_to :item, polymorphic: true
20
- end
21
-
19
+ belongs_to :item, polymorphic: true, optional: true
22
20
  validates_presence_of :event
23
21
  after_create :enforce_version_limit!
24
22
  end
@@ -42,40 +40,7 @@ module PaperTrail
42
40
  end
43
41
 
44
42
  def not_creates
45
- where "event <> ?", "create"
46
- end
47
-
48
- # Returns versions after `obj`.
49
- #
50
- # @param obj - a `Version` or a timestamp
51
- # @param timestamp_arg - boolean - When true, `obj` is a timestamp.
52
- # Default: false.
53
- # @return `ActiveRecord::Relation`
54
- # @api public
55
- def subsequent(obj, timestamp_arg = false)
56
- if timestamp_arg != true && primary_key_is_int?
57
- return where(arel_table[primary_key].gt(obj.id)).order(arel_table[primary_key].asc)
58
- end
59
-
60
- obj = obj.send(:created_at) if obj.is_a?(self)
61
- where(arel_table[:created_at].gt(obj)).order(timestamp_sort_order)
62
- end
63
-
64
- # Returns versions before `obj`.
65
- #
66
- # @param obj - a `Version` or a timestamp
67
- # @param timestamp_arg - boolean - When true, `obj` is a timestamp.
68
- # Default: false.
69
- # @return `ActiveRecord::Relation`
70
- # @api public
71
- def preceding(obj, timestamp_arg = false)
72
- if timestamp_arg != true && primary_key_is_int?
73
- return where(arel_table[primary_key].lt(obj.id)).order(arel_table[primary_key].desc)
74
- end
75
-
76
- obj = obj.send(:created_at) if obj.is_a?(self)
77
- where(arel_table[:created_at].lt(obj)).
78
- order(timestamp_sort_order("desc"))
43
+ where.not(event: "create")
79
44
  end
80
45
 
81
46
  def between(start_time, end_time)
@@ -93,6 +58,18 @@ module PaperTrail
93
58
  end
94
59
  end
95
60
 
61
+ # Given an attribute like `"name"`, query the `versions.object_changes`
62
+ # column for any changes that modified the provided attribute.
63
+ #
64
+ # @api public
65
+ def where_attribute_changes(attribute)
66
+ unless attribute.is_a?(String) || attribute.is_a?(Symbol)
67
+ raise ArgumentError, "expected to receive a String or Symbol"
68
+ end
69
+
70
+ Queries::Versions::WhereAttributeChanges.new(self, attribute).execute
71
+ end
72
+
96
73
  # Given a hash of attributes like `name: 'Joan'`, query the
97
74
  # `versions.objects` column.
98
75
  #
@@ -149,6 +126,36 @@ module PaperTrail
149
126
  Queries::Versions::WhereObjectChanges.new(self, args).execute
150
127
  end
151
128
 
129
+ # Given a hash of attributes like `name: 'Joan'`, query the
130
+ # `versions.objects_changes` column for changes where the version changed
131
+ # from the hash of attributes to other values.
132
+ #
133
+ # This is useful for finding versions where the attribute started with a
134
+ # known value and changed to something else. This is in comparison to
135
+ # `where_object_changes` which will find both the changes before and
136
+ # after.
137
+ #
138
+ # @api public
139
+ def where_object_changes_from(args = {})
140
+ raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
141
+ Queries::Versions::WhereObjectChangesFrom.new(self, args).execute
142
+ end
143
+
144
+ # Given a hash of attributes like `name: 'Joan'`, query the
145
+ # `versions.objects_changes` column for changes where the version changed
146
+ # to the hash of attributes from other values.
147
+ #
148
+ # This is useful for finding versions where the attribute started with an
149
+ # unknown value and changed to a known value. This is in comparison to
150
+ # `where_object_changes` which will find both the changes before and
151
+ # after.
152
+ #
153
+ # @api public
154
+ def where_object_changes_to(args = {})
155
+ raise ArgumentError, "expected to receive a Hash" unless args.is_a?(Hash)
156
+ Queries::Versions::WhereObjectChangesTo.new(self, args).execute
157
+ end
158
+
152
159
  def primary_key_is_int?
153
160
  @primary_key_is_int ||= columns_hash[primary_key].type == :integer
154
161
  rescue StandardError # TODO: Rescue something more specific
@@ -166,6 +173,65 @@ module PaperTrail
166
173
  def object_changes_col_is_json?
167
174
  %i[json jsonb].include?(columns_hash["object_changes"].try(:type))
168
175
  end
176
+
177
+ # Returns versions before `obj`.
178
+ #
179
+ # @param obj - a `Version` or a timestamp
180
+ # @param timestamp_arg - boolean - When true, `obj` is a timestamp.
181
+ # Default: false.
182
+ # @return `ActiveRecord::Relation`
183
+ # @api public
184
+ # rubocop:disable Style/OptionalBooleanParameter
185
+ def preceding(obj, timestamp_arg = false)
186
+ if timestamp_arg != true && primary_key_is_int?
187
+ preceding_by_id(obj)
188
+ else
189
+ preceding_by_timestamp(obj)
190
+ end
191
+ end
192
+ # rubocop:enable Style/OptionalBooleanParameter
193
+
194
+ # Returns versions after `obj`.
195
+ #
196
+ # @param obj - a `Version` or a timestamp
197
+ # @param timestamp_arg - boolean - When true, `obj` is a timestamp.
198
+ # Default: false.
199
+ # @return `ActiveRecord::Relation`
200
+ # @api public
201
+ # rubocop:disable Style/OptionalBooleanParameter
202
+ def subsequent(obj, timestamp_arg = false)
203
+ if timestamp_arg != true && primary_key_is_int?
204
+ subsequent_by_id(obj)
205
+ else
206
+ subsequent_by_timestamp(obj)
207
+ end
208
+ end
209
+ # rubocop:enable Style/OptionalBooleanParameter
210
+
211
+ private
212
+
213
+ # @api private
214
+ def preceding_by_id(obj)
215
+ where(arel_table[primary_key].lt(obj.id)).order(arel_table[primary_key].desc)
216
+ end
217
+
218
+ # @api private
219
+ def preceding_by_timestamp(obj)
220
+ obj = obj.send(:created_at) if obj.is_a?(self)
221
+ where(arel_table[:created_at].lt(obj)).
222
+ order(timestamp_sort_order("desc"))
223
+ end
224
+
225
+ # @api private
226
+ def subsequent_by_id(version)
227
+ where(arel_table[primary_key].gt(version.id)).order(arel_table[primary_key].asc)
228
+ end
229
+
230
+ # @api private
231
+ def subsequent_by_timestamp(obj)
232
+ obj = obj.send(:created_at) if obj.is_a?(self)
233
+ where(arel_table[:created_at].gt(obj)).order(timestamp_sort_order)
234
+ end
169
235
  end
170
236
 
171
237
  # @api private
@@ -179,18 +245,8 @@ module PaperTrail
179
245
 
180
246
  # Restore the item from this version.
181
247
  #
182
- # Optionally this can also restore all :has_one and :has_many (including
183
- # has_many :through) associations as they were "at the time", if they are
184
- # also being versioned by PaperTrail.
185
- #
186
248
  # Options:
187
249
  #
188
- # - :has_one
189
- # - `true` - Also reify has_one associations.
190
- # - `false - Default.
191
- # - :has_many
192
- # - `true` - Also reify has_many and has_many :through associations.
193
- # - `false` - Default.
194
250
  # - :mark_for_destruction
195
251
  # - `true` - Mark the has_one/has_many associations that did not exist in
196
252
  # the reified version for destruction, instead of removing them.
@@ -205,6 +261,9 @@ module PaperTrail
205
261
  # - `:preserve` - Attributes undefined in version record are not modified.
206
262
  #
207
263
  def reify(options = {})
264
+ unless self.class.column_names.include? "object"
265
+ raise Error, "reify requires an object column"
266
+ end
208
267
  return nil if object.nil?
209
268
  ::PaperTrail::Reifier.reify(self, options)
210
269
  end
@@ -229,13 +288,6 @@ module PaperTrail
229
288
  end
230
289
  alias version_author terminator
231
290
 
232
- def sibling_versions(reload = false)
233
- if reload || !defined?(@sibling_versions) || @sibling_versions.nil?
234
- @sibling_versions = self.class.with_item_keys(item_type, item_id)
235
- end
236
- @sibling_versions
237
- end
238
-
239
291
  def next
240
292
  @next ||= sibling_versions.subsequent(self).first
241
293
  end
@@ -245,8 +297,9 @@ module PaperTrail
245
297
  end
246
298
 
247
299
  # Returns an integer representing the chronological position of the
248
- # version among its siblings (see `sibling_versions`). The "create" event,
249
- # for example, has an index of 0.
300
+ # version among its siblings. The "create" event, for example, has an index
301
+ # of 0.
302
+ #
250
303
  # @api public
251
304
  def index
252
305
  @index ||= RecordHistory.new(sibling_versions, self.class).index(self)
@@ -256,7 +309,7 @@ module PaperTrail
256
309
 
257
310
  # @api private
258
311
  def load_changeset
259
- if PaperTrail.config.object_changes_adapter
312
+ if PaperTrail.config.object_changes_adapter.respond_to?(:load_changeset)
260
313
  return PaperTrail.config.object_changes_adapter.load_changeset(self)
261
314
  end
262
315
 
@@ -304,7 +357,7 @@ module PaperTrail
304
357
  # Enforces the `version_limit`, if set. Default: no limit.
305
358
  # @api private
306
359
  def enforce_version_limit!
307
- limit = PaperTrail.config.version_limit
360
+ limit = version_limit
308
361
  return unless limit.is_a? Numeric
309
362
  previous_versions = sibling_versions.not_creates.
310
363
  order(self.class.timestamp_sort_order("asc"))
@@ -312,5 +365,32 @@ module PaperTrail
312
365
  excess_versions = previous_versions - previous_versions.last(limit)
313
366
  excess_versions.map(&:destroy)
314
367
  end
368
+
369
+ # @api private
370
+ def sibling_versions
371
+ @sibling_versions ||= self.class.with_item_keys(item_type, item_id)
372
+ end
373
+
374
+ # See docs section 2.e. Limiting the Number of Versions Created.
375
+ # The version limit can be global or per-model.
376
+ #
377
+ # @api private
378
+ def version_limit
379
+ if limit_option?(item.class)
380
+ item.class.paper_trail_options[:limit]
381
+ elsif base_class_limit_option?(item.class)
382
+ item.class.base_class.paper_trail_options[:limit]
383
+ else
384
+ PaperTrail.config.version_limit
385
+ end
386
+ end
387
+
388
+ def limit_option?(klass)
389
+ klass.respond_to?(:paper_trail_options) && klass.paper_trail_options.key?(:limit)
390
+ end
391
+
392
+ def base_class_limit_option?(klass)
393
+ klass.respond_to?(:base_class) && limit_option?(klass.base_class)
394
+ end
315
395
  end
316
396
  end
@@ -7,8 +7,8 @@ module PaperTrail
7
7
  # because of this confusion, but it's not worth the breaking change.
8
8
  # People are encouraged to use `PaperTrail.gem_version` instead.
9
9
  module VERSION
10
- MAJOR = 9
11
- MINOR = 2
10
+ MAJOR = 12
11
+ MINOR = 1
12
12
  TINY = 0
13
13
 
14
14
  # Set PRE to nil unless it's a pre-release (beta, rc, etc.)
data/lib/paper_trail.rb CHANGED
@@ -8,33 +8,18 @@
8
8
  # can revisit this decision.
9
9
  require "active_support/all"
10
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
-
17
- require "request_store"
11
+ require "paper_trail/errors"
18
12
  require "paper_trail/cleaner"
13
+ require "paper_trail/compatibility"
19
14
  require "paper_trail/config"
20
- require "paper_trail/has_paper_trail"
21
15
  require "paper_trail/record_history"
22
- require "paper_trail/reifier"
23
16
  require "paper_trail/request"
24
- require "paper_trail/version_concern"
25
17
  require "paper_trail/version_number"
26
18
  require "paper_trail/serializers/json"
27
- require "paper_trail/serializers/yaml"
28
19
 
29
20
  # An ActiveRecord extension that tracks changes to your models, for auditing or
30
21
  # versioning.
31
22
  module PaperTrail
32
- E_RAILS_NOT_LOADED = <<-EOS.squish.freeze
33
- PaperTrail has been loaded too early, before rails is loaded. This can
34
- happen when another gem defines the ::Rails namespace, then PT is loaded,
35
- all before rails is loaded. You may want to reorder your Gemfile, or defer
36
- the loading of PT by using `require: false` and a manual require elsewhere.
37
- EOS
38
23
  E_TIMESTAMP_FIELD_CONFIG = <<-EOS.squish.freeze
39
24
  PaperTrail.timestamp_field= has been removed, without replacement. It is no
40
25
  longer configurable. The timestamp column in the versions table must now be
@@ -57,46 +42,6 @@ module PaperTrail
57
42
  !!PaperTrail.config.enabled
58
43
  end
59
44
 
60
- # @deprecated
61
- def enabled_for_controller=(value)
62
- ::ActiveSupport::Deprecation.warn(
63
- "PaperTrail.enabled_for_controller= is deprecated, " \
64
- "use PaperTrail.request.enabled=",
65
- caller(1)
66
- )
67
- request.enabled = value
68
- end
69
-
70
- # @deprecated
71
- def enabled_for_controller?
72
- ::ActiveSupport::Deprecation.warn(
73
- "PaperTrail.enabled_for_controller? is deprecated, " \
74
- "use PaperTrail.request.enabled?",
75
- caller(1)
76
- )
77
- request.enabled?
78
- end
79
-
80
- # @deprecated
81
- def enabled_for_model(model, value)
82
- ::ActiveSupport::Deprecation.warn(
83
- "PaperTrail.enabled_for_model is deprecated, " \
84
- "use PaperTrail.request.enabled_for_model",
85
- caller(1)
86
- )
87
- request.enabled_for_model(model, value)
88
- end
89
-
90
- # @deprecated
91
- def enabled_for_model?(model)
92
- ::ActiveSupport::Deprecation.warn(
93
- "PaperTrail.enabled_for_model? is deprecated, " \
94
- "use PaperTrail.request.enabled_for_model?",
95
- caller(1)
96
- )
97
- request.enabled_for_model?(model)
98
- end
99
-
100
45
  # Returns PaperTrail's `::Gem::Version`, convenient for comparisons. This is
101
46
  # recommended over `::PaperTrail::VERSION::STRING`.
102
47
  #
@@ -124,7 +69,7 @@ module PaperTrail
124
69
  #
125
70
  # @api public
126
71
  def request(options = nil, &block)
127
- if options.nil? && !block_given?
72
+ if options.nil? && !block
128
73
  Request
129
74
  else
130
75
  Request.with(options, &block)
@@ -134,54 +79,7 @@ module PaperTrail
134
79
  # Set the field which records when a version was created.
135
80
  # @api public
136
81
  def timestamp_field=(_field_name)
137
- raise(E_TIMESTAMP_FIELD_CONFIG)
138
- end
139
-
140
- # @deprecated
141
- def whodunnit=(value)
142
- ::ActiveSupport::Deprecation.warn(
143
- "PaperTrail.whodunnit= is deprecated, use PaperTrail.request.whodunnit=",
144
- caller(1)
145
- )
146
- request.whodunnit = value
147
- end
148
-
149
- # @deprecated
150
- def whodunnit(value = nil, &block)
151
- if value.nil?
152
- ::ActiveSupport::Deprecation.warn(
153
- "PaperTrail.whodunnit is deprecated, use PaperTrail.request.whodunnit",
154
- caller(1)
155
- )
156
- request.whodunnit
157
- elsif block_given?
158
- ::ActiveSupport::Deprecation.warn(
159
- "Passing a block to PaperTrail.whodunnit is deprecated, " \
160
- 'use PaperTrail.request(whodunnit: "John") do .. end',
161
- caller(1)
162
- )
163
- request(whodunnit: value, &block)
164
- else
165
- raise ArgumentError, "Invalid arguments"
166
- end
167
- end
168
-
169
- # @deprecated
170
- def controller_info=(value)
171
- ::ActiveSupport::Deprecation.warn(
172
- "PaperTrail.controller_info= is deprecated, use PaperTrail.request.controller_info=",
173
- caller(1)
174
- )
175
- request.controller_info = value
176
- end
177
-
178
- # @deprecated
179
- def controller_info
180
- ::ActiveSupport::Deprecation.warn(
181
- "PaperTrail.controller_info is deprecated, use PaperTrail.request.controller_info",
182
- caller(1)
183
- )
184
- request.controller_info
82
+ raise Error, E_TIMESTAMP_FIELD_CONFIG
185
83
  end
186
84
 
187
85
  # Set the PaperTrail serializer. This setting affects all threads.
@@ -212,23 +110,18 @@ module PaperTrail
212
110
  end
213
111
  end
214
112
 
215
- ActiveSupport.on_load(:active_record) do
216
- include PaperTrail::Model
217
- end
218
-
219
- # Require frameworks
220
- if defined?(::Rails)
221
- # Rails module is sometimes defined by gems like rails-html-sanitizer
222
- # so we check for presence of Rails.application.
223
- if defined?(::Rails.application)
224
- require "paper_trail/frameworks/rails"
225
- else
226
- ::Kernel.warn(::PaperTrail::E_RAILS_NOT_LOADED)
227
- end
113
+ # PT is built on ActiveRecord, but does not require Rails. If Rails is defined,
114
+ # our Railtie makes sure not to load the AR-dependent parts of PT until AR is
115
+ # ready. A typical Rails `application.rb` has:
116
+ #
117
+ # ```
118
+ # require 'rails/all' # Defines `Rails`
119
+ # Bundler.require(*Rails.groups) # require 'paper_trail' (this file)
120
+ # ```
121
+ #
122
+ # Non-rails applications should take similar care to load AR before PT.
123
+ if defined?(Rails)
124
+ require "paper_trail/frameworks/rails"
228
125
  else
229
126
  require "paper_trail/frameworks/active_record"
230
127
  end
231
-
232
- # https://github.com/paper-trail-gem/paper_trail/issues/1070
233
- # https://github.com/westonganger/paper_trail-association_tracking/issues/2
234
- require "paper_trail-association_tracking"