mongo_trails 17.0.1 → 17.1.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.
- checksums.yaml +4 -4
- data/README.md +15 -16
- data/gemfiles/rails_7.gemfile.lock +2 -2
- data/gemfiles/rails_8.gemfile.lock +2 -2
- data/gemfiles/rails_8_1.gemfile.lock +1 -1
- data/gemfiles/rails_8_paper_trail_16.gemfile.lock +2 -2
- data/lib/mongo_trails/config.rb +5 -1
- data/lib/mongo_trails/mongo_support/version.rb +74 -11
- data/lib/mongo_trails/mongo_support/write_version_worker.rb +5 -1
- data/lib/mongo_trails/record_trail.rb +4 -17
- data/lib/mongo_trails/version.rb +1 -1
- data/lib/mongo_trails.rb +0 -1
- metadata +1 -2
- data/lib/mongo_trails/restorable.rb +0 -46
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 56dbb9f210528411b5b75400afafe8cedb67a22c9fe815534cf5702ffde9dfc0
|
|
4
|
+
data.tar.gz: 1b7e64ade5beddbaedb94c28ce4643373314994776e94a67e4af4b2340773b53
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 87875ed778feadc9e4d0b36716e12beb84fddf893aae69b222140cbaccf2dfb9ad600c2ef12da86d76c5c1340b25308ba1c138e13d07cfa11ca23f2a10175159
|
|
7
|
+
data.tar.gz: f034ef6b1babac2f7952d12865730e9bf7cbc1c5bcd00f8f1e570d5ad7ae2773c83aaec8167e40d3341b2670d709854ae8973191de018e63ee13343f3b5883d8
|
data/README.md
CHANGED
|
@@ -33,22 +33,6 @@ require 'mongo_trails/mongo_support/config'
|
|
|
33
33
|
|
|
34
34
|
Done!
|
|
35
35
|
|
|
36
|
-
## Restores
|
|
37
|
-
|
|
38
|
-
Paper Trail records `create`, `update` and `destroy`, but a soft-deleted record brought back by [Paranoia](https://github.com/rubysherpas/paranoia) is restored with `update_columns`, which Paper Trail never sees. Include `MongoTrails::Restorable` in a Paranoia model to record a version with event `restore` (`MongoTrails::RESTORE_EVENT`) each time it is restored:
|
|
39
|
-
|
|
40
|
-
```ruby
|
|
41
|
-
class Post < ActiveRecord::Base
|
|
42
|
-
acts_as_paranoid
|
|
43
|
-
has_paper_trail
|
|
44
|
-
include MongoTrails::Restorable # after acts_as_paranoid, which defines the restore callbacks
|
|
45
|
-
end
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
The version's changes are the columns Paranoia writes on restore (`paranoia_restore_attributes`), from their deleted values to the restored ones. Associated records Paranoia leaves deleted (outside the recovery window) get no version. Paranoia is not a dependency of this gem.
|
|
49
|
-
|
|
50
|
-
To record a restore done some other way, call `record.paper_trail.record_restore(changes)` with each restored column mapped to `[before, after]`, for example `{ 'deleted_at' => [deleted_at, nil] }`. Like `record_update_columns`, it does nothing while Paper Trail is disabled and respects the record size limit.
|
|
51
|
-
|
|
52
36
|
## Config Options
|
|
53
37
|
|
|
54
38
|
`PaperTrail.config.mongo_config = { hosts: ['localhost:27017'], database: 'my_test_db' }` - Options for MongoDB connection
|
|
@@ -59,6 +43,21 @@ To record a restore done some other way, call `record.paper_trail.record_restore
|
|
|
59
43
|
`PaperTrail.config.sidekiq_worker = PaperTrail::WriteVersionWorker` - Worker class
|
|
60
44
|
`PaperTrail.config.sidekiq_options = { queue: :default }` - Options for Sidekiq
|
|
61
45
|
|
|
46
|
+
`PaperTrail.config.enable_integer_id = true` - Give every version a sequential `integer_id` from a per-collection counter, and order previous/next versions by it. With `false` no counter is used, `integer_id` stays empty and versions are ordered by `created_at`. The first write to a collection with no counter scans the whole collection for its highest `integer_id`, which is expensive on large collections (and on DocumentDB, where no index serves it).
|
|
47
|
+
|
|
48
|
+
`PaperTrail.config.on_write_error = nil` - A callable receiving `(error, version)` when a version write fails because MongoDB is unreachable or drops the connection (`MongoTrails::Version::WRITE_ERRORS`). Inside a transaction versions are written from the after-commit callbacks, so a raising write skips every after-commit callback behind it; a handler lets them run. Without a handler the error raises. Other errors always raise.
|
|
49
|
+
|
|
50
|
+
```ruby
|
|
51
|
+
PaperTrail.config.on_write_error = lambda do |error, version|
|
|
52
|
+
ErrorReporter.report(error, item_type: version.item_type, item_id: version.item_id)
|
|
53
|
+
version.enqueue_write unless PaperTrail.config.enable_sidekiq # retry through Sidekiq
|
|
54
|
+
end
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
`PaperTrail::WriteVersionWorker` rebuilds the queued version with `MongoTrails::Version.rebuild` (its `_id`, `created_at` and metadata are kept, `#initialize` is not run again), and treats a version whose `_id` is already stored as written, so a retried write is safe.
|
|
58
|
+
|
|
59
|
+
`MongoTrails::Version.bulk_insert(versions)` - Inserts many versions in one `insert_many`, allocating their `integer_id`s in one counter update when `enable_integer_id` is on.
|
|
60
|
+
|
|
62
61
|
## Releasing
|
|
63
62
|
|
|
64
63
|
Update `MongoTrails::VERSION` and all appraisal lockfiles, then validate and release:
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
mongo_trails (17.0
|
|
4
|
+
mongo_trails (17.1.0)
|
|
5
5
|
mongoid (>= 7, < 10)
|
|
6
6
|
ostruct
|
|
7
7
|
paper_trail (>= 16, < 18)
|
|
@@ -172,7 +172,7 @@ CHECKSUMS
|
|
|
172
172
|
mcp (0.8.0) sha256=ae8bd146bb8e168852866fd26f805f52744f6326afb3211e073f78a95e0c34fb
|
|
173
173
|
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
174
174
|
mongo (2.25.0) sha256=b4663884d23523d24f50c579846956444410f939093e8c2a95fa4b76bb929053
|
|
175
|
-
mongo_trails (17.0
|
|
175
|
+
mongo_trails (17.1.0)
|
|
176
176
|
mongoid (9.1.0) sha256=ef7b50f4c84e636850c3431bc3c92f98481f4e1d147ff06a1c21242d0b242a9e
|
|
177
177
|
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
|
|
178
178
|
paper_trail (17.0.0) sha256=1c2842061d3874ca7015908e821e2aa14f9b982af2acb2a7974713bf79021c85
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
mongo_trails (17.0
|
|
4
|
+
mongo_trails (17.1.0)
|
|
5
5
|
mongoid (>= 7, < 10)
|
|
6
6
|
ostruct
|
|
7
7
|
paper_trail (>= 16, < 18)
|
|
@@ -172,7 +172,7 @@ CHECKSUMS
|
|
|
172
172
|
mcp (0.8.0) sha256=ae8bd146bb8e168852866fd26f805f52744f6326afb3211e073f78a95e0c34fb
|
|
173
173
|
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
174
174
|
mongo (2.25.0) sha256=b4663884d23523d24f50c579846956444410f939093e8c2a95fa4b76bb929053
|
|
175
|
-
mongo_trails (17.0
|
|
175
|
+
mongo_trails (17.1.0)
|
|
176
176
|
mongoid (9.1.0) sha256=ef7b50f4c84e636850c3431bc3c92f98481f4e1d147ff06a1c21242d0b242a9e
|
|
177
177
|
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
|
|
178
178
|
paper_trail (17.0.0) sha256=1c2842061d3874ca7015908e821e2aa14f9b982af2acb2a7974713bf79021c85
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: ..
|
|
3
3
|
specs:
|
|
4
|
-
mongo_trails (17.0
|
|
4
|
+
mongo_trails (17.1.0)
|
|
5
5
|
mongoid (>= 7, < 10)
|
|
6
6
|
ostruct
|
|
7
7
|
paper_trail (>= 16, < 18)
|
|
@@ -175,7 +175,7 @@ CHECKSUMS
|
|
|
175
175
|
mcp (0.8.0) sha256=ae8bd146bb8e168852866fd26f805f52744f6326afb3211e073f78a95e0c34fb
|
|
176
176
|
minitest (5.27.0) sha256=2d3b17f8a36fe7801c1adcffdbc38233b938eb0b4966e97a6739055a45fa77d5
|
|
177
177
|
mongo (2.25.0) sha256=b4663884d23523d24f50c579846956444410f939093e8c2a95fa4b76bb929053
|
|
178
|
-
mongo_trails (17.0
|
|
178
|
+
mongo_trails (17.1.0)
|
|
179
179
|
mongoid (9.1.0) sha256=ef7b50f4c84e636850c3431bc3c92f98481f4e1d147ff06a1c21242d0b242a9e
|
|
180
180
|
ostruct (0.6.3) sha256=95a2ed4a4bd1d190784e666b47b2d3f078e4a9efda2fccf18f84ddc6538ed912
|
|
181
181
|
paper_trail (16.0.0) sha256=e9b9f0fb1b8b590c8231cfa931b282ba92f90e066e393930a5e1c61ae4c5019d
|
data/lib/mongo_trails/config.rb
CHANGED
|
@@ -8,7 +8,9 @@ module PaperTrail
|
|
|
8
8
|
:enable_sidekiq,
|
|
9
9
|
:sidekiq_worker,
|
|
10
10
|
:sidekiq_options,
|
|
11
|
-
:mongo_trails_config
|
|
11
|
+
:mongo_trails_config,
|
|
12
|
+
:enable_integer_id,
|
|
13
|
+
:on_write_error
|
|
12
14
|
)
|
|
13
15
|
|
|
14
16
|
def initialize
|
|
@@ -19,6 +21,8 @@ module PaperTrail
|
|
|
19
21
|
@has_paper_trail_defaults = {}
|
|
20
22
|
@enable_sidekiq = false
|
|
21
23
|
@sidekiq_options = { queue: :default, retry: true, backtrace: false }
|
|
24
|
+
@enable_integer_id = true
|
|
25
|
+
@on_write_error = nil
|
|
22
26
|
end
|
|
23
27
|
end
|
|
24
28
|
end
|
|
@@ -24,9 +24,35 @@ PaperTrail.config.has_paper_trail_defaults = { versions: { class_name: 'MongoTra
|
|
|
24
24
|
|
|
25
25
|
module MongoTrails
|
|
26
26
|
class Version
|
|
27
|
+
# Errors a version write can raise when MongoDB is unreachable or drops the connection. Only these reach
|
|
28
|
+
# PaperTrail.config.on_write_error; anything else (a validation error, a bug) still raises.
|
|
29
|
+
WRITE_ERRORS = [Mongo::Error, IOError, SystemCallError, Timeout::Error].freeze
|
|
30
|
+
DUPLICATE_KEY_ERROR_CODE = 11_000
|
|
31
|
+
|
|
27
32
|
class << self
|
|
28
33
|
def find(id)
|
|
29
|
-
find_by(integer_id: id)
|
|
34
|
+
integer_id_enabled? ? find_by(integer_id: id) : super
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def integer_id_enabled?
|
|
38
|
+
PaperTrail.config.enable_integer_id != false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
# PaperTrail orders previous/next versions by primary key when it is an integer, which here means integer_id.
|
|
42
|
+
# Without integer_id they are ordered by created_at.
|
|
43
|
+
def primary_key_is_int?
|
|
44
|
+
integer_id_enabled?
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
# Rebuilds a version from the JSON of one that was already built (see #enqueue_write), keeping its _id,
|
|
48
|
+
# created_at and metadata. It does not run #initialize, so build-time defaults are not applied a second time.
|
|
49
|
+
def rebuild(attributes)
|
|
50
|
+
document = attributes.to_h.stringify_keys.to_h { |name, value| [name, from_json_value(name, value)] }
|
|
51
|
+
instantiate(document).tap { |version| version.new_record = true }
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
def duplicate_key_error?(error)
|
|
55
|
+
error.respond_to?(:code) && error.code == DUPLICATE_KEY_ERROR_CODE
|
|
30
56
|
end
|
|
31
57
|
|
|
32
58
|
def incrementing_fields
|
|
@@ -62,6 +88,17 @@ module MongoTrails
|
|
|
62
88
|
((max_integer_id - count + 1)..max_integer_id).to_a
|
|
63
89
|
end
|
|
64
90
|
|
|
91
|
+
def bulk_insert(versions)
|
|
92
|
+
return [] if versions.empty?
|
|
93
|
+
|
|
94
|
+
documents = versions.map { |version| bulk_insert_attributes(version) }
|
|
95
|
+
if integer_id_enabled?
|
|
96
|
+
integer_ids = next_integer_ids(documents.count { |document| document['integer_id'].nil? })
|
|
97
|
+
documents.each { |document| document['integer_id'] ||= integer_ids.shift }
|
|
98
|
+
end
|
|
99
|
+
collection.insert_many(documents)
|
|
100
|
+
end
|
|
101
|
+
|
|
65
102
|
def bulk_insert_attributes(version)
|
|
66
103
|
version = version.is_a?(self) ? version : new(version)
|
|
67
104
|
attrs = version.attributes.dup
|
|
@@ -91,6 +128,17 @@ module MongoTrails
|
|
|
91
128
|
|
|
92
129
|
private
|
|
93
130
|
|
|
131
|
+
# as_json turns ObjectIds and times into strings; every other field type survives JSON as is.
|
|
132
|
+
def from_json_value(name, value)
|
|
133
|
+
return value unless value.is_a?(String)
|
|
134
|
+
|
|
135
|
+
type = fields[name]&.type
|
|
136
|
+
return BSON::ObjectId.legal?(value) ? BSON::ObjectId.from_string(value) : value if type == BSON::ObjectId
|
|
137
|
+
return (Time.zone || Time).parse(value) if [Time, DateTime].include?(type)
|
|
138
|
+
|
|
139
|
+
value
|
|
140
|
+
end
|
|
141
|
+
|
|
94
142
|
def counter_key(scope)
|
|
95
143
|
"#{name}:#{scope || prefix_map}"
|
|
96
144
|
end
|
|
@@ -152,6 +200,17 @@ module MongoTrails
|
|
|
152
200
|
schedule_version_persistence(bang: true)
|
|
153
201
|
end
|
|
154
202
|
|
|
203
|
+
# Queues the write of this version for PaperTrail::WriteVersionWorker (or the configured sidekiq_worker).
|
|
204
|
+
def enqueue_write
|
|
205
|
+
worker = defined?(PaperTrail.config.sidekiq_worker.queue) ? PaperTrail.config.sidekiq_worker : PaperTrail::WriteVersionWorker
|
|
206
|
+
args = attributes.as_json
|
|
207
|
+
if worker == PaperTrail::WriteVersionWorker
|
|
208
|
+
worker.set(PaperTrail.config.sidekiq_options).perform_async(args)
|
|
209
|
+
else
|
|
210
|
+
worker.perform_async(args)
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
155
214
|
def initialize(data)
|
|
156
215
|
data = data.to_h.deep_symbolize_keys
|
|
157
216
|
item = data.delete(:item)
|
|
@@ -236,6 +295,8 @@ module MongoTrails
|
|
|
236
295
|
end
|
|
237
296
|
|
|
238
297
|
def assign_integer_id
|
|
298
|
+
return unless self.class.integer_id_enabled?
|
|
299
|
+
|
|
239
300
|
self.integer_id ||= self.class.next_integer_id
|
|
240
301
|
end
|
|
241
302
|
|
|
@@ -248,10 +309,19 @@ module MongoTrails
|
|
|
248
309
|
current_time
|
|
249
310
|
end
|
|
250
311
|
|
|
312
|
+
# Inside a transaction this runs from VersionCommitWrap#committed!, among the source record's after-commit
|
|
313
|
+
# callbacks, so an error raised here skips every callback queued behind it. PaperTrail.config.on_write_error
|
|
314
|
+
# receives the connection errors instead of letting them raise; without a handler they raise as before.
|
|
251
315
|
def persist_version(version, bang: false)
|
|
252
|
-
return version.
|
|
316
|
+
return version.enqueue_write if sidekiq_enabled?
|
|
253
317
|
|
|
254
318
|
bang ? version.save! : version.save
|
|
319
|
+
rescue *WRITE_ERRORS => e
|
|
320
|
+
handler = PaperTrail.config.on_write_error
|
|
321
|
+
raise unless handler
|
|
322
|
+
|
|
323
|
+
handler.call(e, version)
|
|
324
|
+
nil
|
|
255
325
|
end
|
|
256
326
|
|
|
257
327
|
def parse_time(value)
|
|
@@ -273,14 +343,7 @@ module MongoTrails
|
|
|
273
343
|
@parser ||= URI::Parser.new
|
|
274
344
|
end
|
|
275
345
|
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
args = attributes.as_json
|
|
279
|
-
if worker == PaperTrail::WriteVersionWorker
|
|
280
|
-
worker.set(PaperTrail.config.sidekiq_options).perform_async(args)
|
|
281
|
-
else
|
|
282
|
-
worker.perform_async(args)
|
|
283
|
-
end
|
|
284
|
-
end
|
|
346
|
+
# Kept for callers of the old private name; use #enqueue_write.
|
|
347
|
+
alias async_save! enqueue_write
|
|
285
348
|
end
|
|
286
349
|
end
|
|
@@ -4,8 +4,12 @@ module PaperTrail
|
|
|
4
4
|
class WriteVersionWorker
|
|
5
5
|
include Sidekiq::Job
|
|
6
6
|
|
|
7
|
+
# The job carries a version that was already built, so it is rebuilt as is rather than built again. A retry after a
|
|
8
|
+
# write whose acknowledgement was lost finds its _id already stored: the version is written, so the job is done.
|
|
7
9
|
def perform(obj)
|
|
8
|
-
MongoTrails::Version.
|
|
10
|
+
MongoTrails::Version.rebuild(obj).save!
|
|
11
|
+
rescue Mongo::Error::OperationFailure => e
|
|
12
|
+
raise unless MongoTrails::Version.duplicate_key_error?(e)
|
|
9
13
|
end
|
|
10
14
|
end
|
|
11
15
|
end
|
|
@@ -43,23 +43,8 @@ module PaperTrail
|
|
|
43
43
|
def record_update_columns(changes)
|
|
44
44
|
return unless enabled?
|
|
45
45
|
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
# Records a 'restore' version for a soft-deleted record brought back outside Paper Trail's callbacks,
|
|
50
|
-
# e.g. by Paranoia, which writes with update_columns. `changes` maps each restored column to
|
|
51
|
-
# [before, after], such as { 'deleted_at' => [deleted_at, nil] }.
|
|
52
|
-
def record_restore(changes)
|
|
53
|
-
return unless enabled?
|
|
54
|
-
|
|
55
|
-
save_update_columns_version(changes, event: MongoTrails::RESTORE_EVENT)
|
|
56
|
-
end
|
|
57
|
-
|
|
58
|
-
private
|
|
59
|
-
|
|
60
|
-
def save_update_columns_version(changes, event: nil)
|
|
61
|
-
data = Events::Update.new(@record, false, false, changes).data.merge(data_for_update_columns)
|
|
62
|
-
data[:event] = event if event
|
|
46
|
+
event = Events::Update.new(@record, false, false, changes)
|
|
47
|
+
data = event.data.merge(data_for_update_columns)
|
|
63
48
|
versions_assoc = @record.send(@record.class.versions_association_name)
|
|
64
49
|
version = versions_assoc.new(data)
|
|
65
50
|
return if exceeds_record_size_limit?(version)
|
|
@@ -68,6 +53,8 @@ module PaperTrail
|
|
|
68
53
|
version.save_version
|
|
69
54
|
end
|
|
70
55
|
|
|
56
|
+
private
|
|
57
|
+
|
|
71
58
|
def exceeds_record_size_limit?(version)
|
|
72
59
|
size_limit = PaperTrail.config.mongo_trails_config&.dig(:record_size_limit)
|
|
73
60
|
size_limit && size_limit.to_i < version.to_json.to_s.bytesize
|
data/lib/mongo_trails/version.rb
CHANGED
data/lib/mongo_trails.rb
CHANGED
|
@@ -12,7 +12,6 @@ require 'mongo_trails/events/base'
|
|
|
12
12
|
require 'mongo_trails/model_config'
|
|
13
13
|
require 'mongo_trails/version_concern'
|
|
14
14
|
require 'mongo_trails/record_trail'
|
|
15
|
-
require 'mongo_trails/restorable'
|
|
16
15
|
|
|
17
16
|
ActiveSupport.on_load(:active_record) do
|
|
18
17
|
require 'mongo_trails/mongo_support/version'
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: mongo_trails
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 17.0
|
|
4
|
+
version: 17.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Alex Tsirel
|
|
@@ -123,7 +123,6 @@ files:
|
|
|
123
123
|
- lib/mongo_trails/mongo_support/version_commit_wrap.rb
|
|
124
124
|
- lib/mongo_trails/mongo_support/write_version_worker.rb
|
|
125
125
|
- lib/mongo_trails/record_trail.rb
|
|
126
|
-
- lib/mongo_trails/restorable.rb
|
|
127
126
|
- lib/mongo_trails/version.rb
|
|
128
127
|
- lib/mongo_trails/version_concern.rb
|
|
129
128
|
- mongo_trails.gemspec
|
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
# frozen_string_literal: true
|
|
2
|
-
|
|
3
|
-
module MongoTrails
|
|
4
|
-
# Paper Trail event of the version recorded when a soft-deleted record is restored (RecordTrail#record_restore)
|
|
5
|
-
RESTORE_EVENT = 'restore'
|
|
6
|
-
|
|
7
|
-
# Records a 'restore' version when a Paranoia model is restored. Paranoia restores with update_columns,
|
|
8
|
-
# which Paper Trail never sees, so the version history would otherwise jump from 'destroy' to the next update.
|
|
9
|
-
#
|
|
10
|
-
# class Post < ActiveRecord::Base
|
|
11
|
-
# acts_as_paranoid
|
|
12
|
-
# has_paper_trail
|
|
13
|
-
# include MongoTrails::Restorable
|
|
14
|
-
# end
|
|
15
|
-
#
|
|
16
|
-
# Include it after acts_as_paranoid, which defines the restore callbacks. The version's changes are the columns
|
|
17
|
-
# Paranoia writes on restore (paranoia_restore_attributes), from their deleted values to the restored ones.
|
|
18
|
-
# Paranoia runs the callbacks for associated records outside the recovery window too, so only a record that
|
|
19
|
-
# was actually restored gets a version.
|
|
20
|
-
module Restorable
|
|
21
|
-
extend ActiveSupport::Concern
|
|
22
|
-
|
|
23
|
-
included do
|
|
24
|
-
before_restore :remember_mongo_trails_deleted_attributes
|
|
25
|
-
after_restore :record_mongo_trails_restore
|
|
26
|
-
end
|
|
27
|
-
|
|
28
|
-
private
|
|
29
|
-
|
|
30
|
-
def remember_mongo_trails_deleted_attributes
|
|
31
|
-
@mongo_trails_deleted_attributes = paranoia_destroyed? ? attributes.slice(*mongo_trails_restore_columns) : nil
|
|
32
|
-
end
|
|
33
|
-
|
|
34
|
-
def record_mongo_trails_restore
|
|
35
|
-
deleted_attributes = @mongo_trails_deleted_attributes
|
|
36
|
-
@mongo_trails_deleted_attributes = nil
|
|
37
|
-
return if deleted_attributes.nil? || paranoia_destroyed?
|
|
38
|
-
|
|
39
|
-
paper_trail.record_restore(deleted_attributes.to_h { |column, value| [column, [value, self[column]]] })
|
|
40
|
-
end
|
|
41
|
-
|
|
42
|
-
def mongo_trails_restore_columns
|
|
43
|
-
send(:paranoia_restore_attributes).keys.map(&:to_s)
|
|
44
|
-
end
|
|
45
|
-
end
|
|
46
|
-
end
|