paper_trail 9.1.1 → 9.2.0

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