paper_trail 9.1.1 → 9.2.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.
@@ -1,11 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require "paper_trail/attribute_serializers/object_attribute"
4
- require "paper_trail/reifiers/belongs_to"
5
- require "paper_trail/reifiers/has_and_belongs_to_many"
6
- require "paper_trail/reifiers/has_many"
7
- require "paper_trail/reifiers/has_many_through"
8
- require "paper_trail/reifiers/has_one"
9
4
 
10
5
  module PaperTrail
11
6
  # Given a version record and some options, builds a new model object.
@@ -20,22 +15,9 @@ module PaperTrail
20
15
  model = init_model(attrs, options, version)
21
16
  reify_attributes(model, version, attrs)
22
17
  model.send "#{model.class.version_association_name}=", version
23
- reify_associations(model, options, version)
24
18
  model
25
19
  end
26
20
 
27
- # Restore the `model`'s has_many associations as they were at version_at
28
- # timestamp We lookup the first child versions after version_at timestamp or
29
- # in same transaction.
30
- # @api private
31
- def reify_has_manys(transaction_id, model, options = {})
32
- assoc_has_many_through, assoc_has_many_directly =
33
- model.class.reflect_on_all_associations(:has_many).
34
- partition { |assoc| assoc.options[:through] }
35
- reify_has_many_associations(transaction_id, assoc_has_many_directly, model, options)
36
- reify_has_many_through_associations(transaction_id, assoc_has_many_through, model, options)
37
- end
38
-
39
21
  private
40
22
 
41
23
  # Given a hash of `options` for `.reify`, return a new hash with default
@@ -53,14 +35,6 @@ module PaperTrail
53
35
  }.merge(options)
54
36
  end
55
37
 
56
- # @api private
57
- def each_enabled_association(associations)
58
- associations.each do |assoc|
59
- next unless ::PaperTrail.request.enabled_for_model?(assoc.klass)
60
- yield assoc
61
- end
62
- end
63
-
64
38
  # Initialize a model object suitable for reifying `version` into. Does
65
39
  # not perform reification, merely instantiates the appropriate model
66
40
  # class and, if specified by `options[:unversioned_attributes]`, sets
@@ -136,70 +110,6 @@ module PaperTrail
136
110
  end
137
111
  end
138
112
 
139
- # @api private
140
- def reify_associations(model, options, version)
141
- if options[:has_one]
142
- reify_has_one_associations(version.transaction_id, model, options)
143
- end
144
- if options[:belongs_to]
145
- reify_belongs_to_associations(version.transaction_id, model, options)
146
- end
147
- if options[:has_many]
148
- reify_has_manys(version.transaction_id, model, options)
149
- end
150
- if options[:has_and_belongs_to_many]
151
- reify_habtm_associations version.transaction_id, model, options
152
- end
153
- end
154
-
155
- # Restore the `model`'s has_one associations as they were when this
156
- # version was superseded by the next (because that's what the user was
157
- # looking at when they made the change).
158
- # @api private
159
- def reify_has_one_associations(transaction_id, model, options = {})
160
- associations = model.class.reflect_on_all_associations(:has_one)
161
- each_enabled_association(associations) do |assoc|
162
- Reifiers::HasOne.reify(assoc, model, options, transaction_id)
163
- end
164
- end
165
-
166
- # Reify all `belongs_to` associations of `model`.
167
- # @api private
168
- def reify_belongs_to_associations(transaction_id, model, options = {})
169
- associations = model.class.reflect_on_all_associations(:belongs_to)
170
- each_enabled_association(associations) do |assoc|
171
- Reifiers::BelongsTo.reify(assoc, model, options, transaction_id)
172
- end
173
- end
174
-
175
- # Reify all direct (not `through`) `has_many` associations of `model`.
176
- # @api private
177
- def reify_has_many_associations(transaction_id, associations, model, options = {})
178
- version_table_name = model.class.paper_trail.version_class.table_name
179
- each_enabled_association(associations) do |assoc|
180
- Reifiers::HasMany.reify(assoc, model, options, transaction_id, version_table_name)
181
- end
182
- end
183
-
184
- # Reify all HMT associations of `model`. This must be called after the
185
- # direct (non-`through`) has_manys have been reified.
186
- # @api private
187
- def reify_has_many_through_associations(transaction_id, associations, model, options = {})
188
- each_enabled_association(associations) do |assoc|
189
- Reifiers::HasManyThrough.reify(assoc, model, options, transaction_id)
190
- end
191
- end
192
-
193
- # Reify all HABTM associations of `model`.
194
- # @api private
195
- def reify_habtm_associations(transaction_id, model, options = {})
196
- model.class.reflect_on_all_associations(:has_and_belongs_to_many).each do |assoc|
197
- pt_enabled = ::PaperTrail.request.enabled_for_model?(assoc.klass)
198
- next unless model.class.paper_trail_save_join_tables.include?(assoc.name) || pt_enabled
199
- Reifiers::HasAndBelongsToMany.reify(pt_enabled, assoc, model, options, transaction_id)
200
- end
201
- end
202
-
203
113
  # Given a `version`, return the class to reify. This method supports
204
114
  # Single Table Inheritance (STI) with custom inheritance columns.
205
115
  #
@@ -16,11 +16,6 @@ module PaperTrail
16
16
  end
17
17
 
18
18
  class << self
19
- # @api private
20
- def clear_transaction_id
21
- self.transaction_id = nil
22
- end
23
-
24
19
  # Sets any data from the controller that you want PaperTrail to store.
25
20
  # See also `PaperTrail::Rails::Controller#info_for_paper_trail`.
26
21
  #
@@ -105,16 +100,6 @@ module PaperTrail
105
100
  store.deep_dup
106
101
  end
107
102
 
108
- # @api private
109
- def transaction_id
110
- store[:transaction_id]
111
- end
112
-
113
- # @api private
114
- def transaction_id=(id)
115
- store[:transaction_id] = id
116
- end
117
-
118
103
  # Temporarily set `options` and execute a block.
119
104
  # @api private
120
105
  def with(options)
@@ -171,8 +156,6 @@ module PaperTrail
171
156
  :enabled,
172
157
  :whodunnit
173
158
  next
174
- when :transaction_id
175
- raise InvalidOption, "Cannot set private option: #{k}"
176
159
  else
177
160
  raise InvalidOption, "Invalid option: #{k}"
178
161
  end
@@ -19,17 +19,8 @@ module PaperTrail
19
19
  belongs_to :item, polymorphic: true
20
20
  end
21
21
 
22
- # Since the test suite has test coverage for this, we want to declare
23
- # the association when the test suite is running. This makes it pass when
24
- # DB is not initialized prior to test runs such as when we run on Travis
25
- # CI (there won't be a db in `spec/dummy_app/db/`).
26
- if PaperTrail.config.track_associations?
27
- has_many :version_associations, dependent: :destroy
28
- end
29
-
30
22
  validates_presence_of :event
31
23
  after_create :enforce_version_limit!
32
- scope(:within_transaction, ->(id) { where transaction_id: id })
33
24
  end
34
25
 
35
26
  # :nodoc:
@@ -265,6 +256,10 @@ module PaperTrail
265
256
 
266
257
  # @api private
267
258
  def load_changeset
259
+ if PaperTrail.config.object_changes_adapter
260
+ return PaperTrail.config.object_changes_adapter.load_changeset(self)
261
+ end
262
+
268
263
  # First, deserialize the `object_changes` column.
269
264
  changes = HashWithIndifferentAccess.new(object_changes_deserialized)
270
265
 
@@ -8,8 +8,8 @@ module PaperTrail
8
8
  # People are encouraged to use `PaperTrail.gem_version` instead.
9
9
  module VERSION
10
10
  MAJOR = 9
11
- MINOR = 1
12
- TINY = 1
11
+ MINOR = 2
12
+ TINY = 0
13
13
 
14
14
  # Set PRE to nil unless it's a pre-release (beta, rc, etc.)
15
15
  PRE = nil
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: paper_trail
3
3
  version: !ruby/object:Gem::Version
4
- version: 9.1.1
4
+ version: 9.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Andy Stewart
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
- date: 2018-05-30 00:00:00.000000000 Z
13
+ date: 2018-06-10 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activerecord
@@ -32,6 +32,20 @@ dependencies:
32
32
  - - "<"
33
33
  - !ruby/object:Gem::Version
34
34
  version: '5.3'
35
+ - !ruby/object:Gem::Dependency
36
+ name: paper_trail-association_tracking
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "<"
40
+ - !ruby/object:Gem::Version
41
+ version: '2'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "<"
47
+ - !ruby/object:Gem::Version
48
+ version: '2'
35
49
  - !ruby/object:Gem::Dependency
36
50
  name: request_store
37
51
  requirement: !ruby/object:Gem::Requirement
@@ -212,8 +226,6 @@ files:
212
226
  - lib/generators/paper_trail/USAGE
213
227
  - lib/generators/paper_trail/install_generator.rb
214
228
  - lib/generators/paper_trail/templates/add_object_changes_to_versions.rb.erb
215
- - lib/generators/paper_trail/templates/add_transaction_id_column_to_versions.rb.erb
216
- - lib/generators/paper_trail/templates/create_version_associations.rb.erb
217
229
  - lib/generators/paper_trail/templates/create_versions.rb.erb
218
230
  - lib/paper_trail.rb
219
231
  - lib/paper_trail/attribute_serializers/README.md
@@ -225,7 +237,6 @@ files:
225
237
  - lib/paper_trail/config.rb
226
238
  - lib/paper_trail/frameworks/active_record.rb
227
239
  - lib/paper_trail/frameworks/active_record/models/paper_trail/version.rb
228
- - lib/paper_trail/frameworks/active_record/models/paper_trail/version_association.rb
229
240
  - lib/paper_trail/frameworks/cucumber.rb
230
241
  - lib/paper_trail/frameworks/rails.rb
231
242
  - lib/paper_trail/frameworks/rails/controller.rb
@@ -239,16 +250,10 @@ files:
239
250
  - lib/paper_trail/record_history.rb
240
251
  - lib/paper_trail/record_trail.rb
241
252
  - lib/paper_trail/reifier.rb
242
- - lib/paper_trail/reifiers/belongs_to.rb
243
- - lib/paper_trail/reifiers/has_and_belongs_to_many.rb
244
- - lib/paper_trail/reifiers/has_many.rb
245
- - lib/paper_trail/reifiers/has_many_through.rb
246
- - lib/paper_trail/reifiers/has_one.rb
247
253
  - lib/paper_trail/request.rb
248
254
  - lib/paper_trail/serializers/json.rb
249
255
  - lib/paper_trail/serializers/yaml.rb
250
256
  - lib/paper_trail/type_serializers/postgres_array_serializer.rb
251
- - lib/paper_trail/version_association_concern.rb
252
257
  - lib/paper_trail/version_concern.rb
253
258
  - lib/paper_trail/version_number.rb
254
259
  homepage: https://github.com/paper-trail-gem/paper_trail
@@ -1,13 +0,0 @@
1
- # This migration and CreateVersionAssociations provide the necessary
2
- # schema for tracking associations.
3
- class AddTransactionIdColumnToVersions < ActiveRecord::Migration<%= migration_version %>
4
- def self.up
5
- add_column :versions, :transaction_id, :integer
6
- add_index :versions, [:transaction_id]
7
- end
8
-
9
- def self.down
10
- remove_index :versions, [:transaction_id]
11
- remove_column :versions, :transaction_id
12
- end
13
- end
@@ -1,22 +0,0 @@
1
- # This migration and AddTransactionIdColumnToVersions provide the necessary
2
- # schema for tracking associations.
3
- class CreateVersionAssociations < ActiveRecord::Migration<%= migration_version %>
4
- def self.up
5
- create_table :version_associations do |t|
6
- t.integer :version_id
7
- t.string :foreign_key_name, null: false
8
- t.integer :foreign_key_id
9
- end
10
- add_index :version_associations, [:version_id]
11
- add_index :version_associations,
12
- %i(foreign_key_name foreign_key_id),
13
- name: "index_version_associations_on_foreign_key"
14
- end
15
-
16
- def self.down
17
- remove_index :version_associations, [:version_id]
18
- remove_index :version_associations,
19
- name: "index_version_associations_on_foreign_key"
20
- drop_table :version_associations
21
- end
22
- end
@@ -1,13 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- require "paper_trail/version_association_concern"
4
-
5
- module PaperTrail
6
- # This is the default ActiveRecord model provided by PaperTrail. Most simple
7
- # applications will only use this and its partner, `Version`, but it is
8
- # possible to sub-class, extend, or even do without this model entirely.
9
- # See the readme for details.
10
- class VersionAssociation < ::ActiveRecord::Base
11
- include PaperTrail::VersionAssociationConcern
12
- end
13
- end
@@ -1,50 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PaperTrail
4
- module Reifiers
5
- # Reify a single `belongs_to` association of `model`.
6
- # @api private
7
- module BelongsTo
8
- class << self
9
- # @api private
10
- def reify(assoc, model, options, transaction_id)
11
- id = model.send(assoc.foreign_key)
12
- version = load_version(assoc, id, transaction_id, options[:version_at])
13
- record = load_record(assoc, id, options, version)
14
- model.send("#{assoc.name}=".to_sym, record)
15
- end
16
-
17
- private
18
-
19
- # Given a `belongs_to` association and a `version`, return a record that
20
- # can be assigned in order to reify that association.
21
- # @api private
22
- def load_record(assoc, id, options, version)
23
- if version.nil?
24
- assoc.klass.where(assoc.klass.primary_key => id).first
25
- else
26
- version.reify(
27
- options.merge(
28
- has_many: false,
29
- has_one: false,
30
- belongs_to: false,
31
- has_and_belongs_to_many: false
32
- )
33
- )
34
- end
35
- end
36
-
37
- # Given a `belongs_to` association and an `id`, return a version record
38
- # from the point in time identified by `transaction_id` or `version_at`.
39
- # @api private
40
- def load_version(assoc, id, transaction_id, version_at)
41
- assoc.klass.paper_trail.version_class.
42
- where("item_type = ?", assoc.klass.base_class.name).
43
- where("item_id = ?", id).
44
- where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
45
- order("id").limit(1).first
46
- end
47
- end
48
- end
49
- end
50
- end
@@ -1,52 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PaperTrail
4
- module Reifiers
5
- # Reify a single HABTM association of `model`.
6
- # @api private
7
- module HasAndBelongsToMany
8
- class << self
9
- # @api private
10
- def reify(pt_enabled, assoc, model, options, transaction_id)
11
- version_ids = ::PaperTrail::VersionAssociation.
12
- where("foreign_key_name = ?", assoc.name).
13
- where("version_id = ?", transaction_id).
14
- pluck(:foreign_key_id)
15
-
16
- model.send(assoc.name).proxy_association.target =
17
- version_ids.map do |id|
18
- if pt_enabled
19
- version = load_version(assoc, id, transaction_id, options[:version_at])
20
- if version
21
- next version.reify(
22
- options.merge(
23
- has_many: false,
24
- has_one: false,
25
- belongs_to: false,
26
- has_and_belongs_to_many: false
27
- )
28
- )
29
- end
30
- end
31
- assoc.klass.where(assoc.klass.primary_key => id).first
32
- end
33
- end
34
-
35
- private
36
-
37
- # Given a HABTM association `assoc` and an `id`, return a version record
38
- # from the point in time identified by `transaction_id` or `version_at`.
39
- # @api private
40
- def load_version(assoc, id, transaction_id, version_at)
41
- assoc.klass.paper_trail.version_class.
42
- where("item_type = ?", assoc.klass.base_class.name).
43
- where("item_id = ?", id).
44
- where("created_at >= ? OR transaction_id = ?", version_at, transaction_id).
45
- order("id").
46
- limit(1).
47
- first
48
- end
49
- end
50
- end
51
- end
52
- end
@@ -1,112 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module PaperTrail
4
- module Reifiers
5
- # Reify a single, direct (not `through`) `has_many` association of `model`.
6
- # @api private
7
- module HasMany
8
- class << self
9
- # @api private
10
- def reify(assoc, model, options, transaction_id, version_table_name)
11
- versions = load_versions_for_hm_association(
12
- assoc,
13
- model,
14
- version_table_name,
15
- transaction_id,
16
- options[:version_at]
17
- )
18
- collection = Array.new model.send(assoc.name).reload # to avoid cache
19
- prepare_array(collection, options, versions)
20
- model.send(assoc.name).proxy_association.target = collection
21
- end
22
-
23
- # Replaces each record in `array` with its reified version, if present
24
- # in `versions`.
25
- #
26
- # @api private
27
- # @param array - The collection to be modified.
28
- # @param options
29
- # @param versions - A `Hash` mapping IDs to `Version`s
30
- # @return nil - Always returns `nil`
31
- #
32
- # Once modified by this method, `array` will be assigned to the
33
- # AR association currently being reified.
34
- #
35
- def prepare_array(array, options, versions)
36
- # Iterate each child to replace it with the previous value if there is
37
- # a version after the timestamp.
38
- array.map! do |record|
39
- if (version = versions.delete(record.id)).nil?
40
- record
41
- elsif version.event == "create"
42
- options[:mark_for_destruction] ? record.tap(&:mark_for_destruction) : nil
43
- else
44
- version.reify(
45
- options.merge(
46
- has_many: false,
47
- has_one: false,
48
- belongs_to: false,
49
- has_and_belongs_to_many: false
50
- )
51
- )
52
- end
53
- end
54
-
55
- # Reify the rest of the versions and add them to the collection, these
56
- # versions are for those that have been removed from the live
57
- # associations.
58
- array.concat(
59
- versions.values.map { |v|
60
- v.reify(
61
- options.merge(
62
- has_many: false,
63
- has_one: false,
64
- belongs_to: false,
65
- has_and_belongs_to_many: false
66
- )
67
- )
68
- }
69
- )
70
-
71
- array.compact!
72
-
73
- nil
74
- end
75
-
76
- # Given a SQL fragment that identifies the IDs of version records,
77
- # returns a `Hash` mapping those IDs to `Version`s.
78
- #
79
- # @api private
80
- # @param klass - An ActiveRecord class.
81
- # @param version_id_subquery - String. A SQL subquery that selects
82
- # the IDs of version records.
83
- # @return A `Hash` mapping IDs to `Version`s
84
- #
85
- def versions_by_id(klass, version_id_subquery)
86
- klass.
87
- paper_trail.version_class.
88
- where("id IN (#{version_id_subquery})").
89
- inject({}) { |a, e| a.merge!(e.item_id => e) }
90
- end
91
-
92
- private
93
-
94
- # Given a `has_many` association on `model`, return the version records
95
- # from the point in time identified by `tx_id` or `version_at`.
96
- # @api private
97
- def load_versions_for_hm_association(assoc, model, version_table, tx_id, version_at)
98
- version_id_subquery = ::PaperTrail::VersionAssociation.
99
- joins(model.class.version_association_name).
100
- select("MIN(version_id)").
101
- where("foreign_key_name = ?", assoc.foreign_key).
102
- where("foreign_key_id = ?", model.id).
103
- where("#{version_table}.item_type = ?", assoc.klass.base_class.name).
104
- where("created_at >= ? OR transaction_id = ?", version_at, tx_id).
105
- group("item_id").
106
- to_sql
107
- versions_by_id(model.class, version_id_subquery)
108
- end
109
- end
110
- end
111
- end
112
- end