hoardable 0.2.0 → 0.3.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 +54 -19
- data/lib/hoardable/hoardable.rb +3 -3
- data/lib/hoardable/model.rb +18 -5
- data/lib/hoardable/source_model.rb +4 -4
- data/lib/hoardable/tableoid.rb +10 -3
- data/lib/hoardable/version.rb +1 -1
- data/sig/hoardable.rbs +3 -3
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 50086ef99aac41454b28ab8bff2e8abf94d7870b371da0c706c477e0b296ffc3
|
4
|
+
data.tar.gz: 6e6d4ab40470bbfb93e23e96fdbb2d8b086878d24e55d499ac368523125e5397
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 747ac52845c950eb655cb7b0af22794dda49ed08e2b0f1aee472595fd2c63b1f886d4f516e686807607efe4946ca588792913ea92ec1c3152a44c23f8cd84487
|
7
|
+
data.tar.gz: 3460ccd66ebe6eed7cdb129bca6150696b82ad9f8613965e80b08fb458ac6e2b8b644e662036533f73f95f52b97a10bf50f2782f76d3fd6671f23f9c2b58df08
|
data/README.md
CHANGED
@@ -69,7 +69,7 @@ Rails 7.
|
|
69
69
|
### Overview
|
70
70
|
|
71
71
|
Once you include `Hoardable::Model` into a model, it will dynamically generate a "Version" subclass
|
72
|
-
of that model. As we continue our example above
|
72
|
+
of that model. As we continue our example above:
|
73
73
|
|
74
74
|
```
|
75
75
|
$ irb
|
@@ -146,7 +146,10 @@ choosing.
|
|
146
146
|
One convenient way to assign contextual data to these is by defining a proc in an initializer, i.e.:
|
147
147
|
|
148
148
|
```ruby
|
149
|
+
# config/initiailzers/hoardable.rb
|
149
150
|
Hoardable.whodunit = -> { Current.user&.id }
|
151
|
+
|
152
|
+
# somewhere in your app code
|
150
153
|
Current.user = User.find(123)
|
151
154
|
post.update!(status: 'live')
|
152
155
|
post.versions.last.hoardable_whodunit # => 123
|
@@ -230,6 +233,7 @@ There are three configurable options currently:
|
|
230
233
|
Hoardable.enabled # => default true
|
231
234
|
Hoardable.version_updates # => default true
|
232
235
|
Hoardable.save_trash # => default true
|
236
|
+
Hoardable.return_everything # => default false
|
233
237
|
```
|
234
238
|
|
235
239
|
`Hoardable.enabled` controls whether versions will be ever be created.
|
@@ -239,6 +243,10 @@ Hoardable.save_trash # => default true
|
|
239
243
|
`Hoardable.save_trash` controls whether to create versions upon record deletion. When this is set to
|
240
244
|
`false`, all versions of a record will be deleted when the record is destroyed.
|
241
245
|
|
246
|
+
`Hoardable.return_everything` controls whether to include versions when doing queries for source
|
247
|
+
models. This is typically only useful to set around a block, as explained below in
|
248
|
+
[Relationships](#relationships).
|
249
|
+
|
242
250
|
If you would like to temporarily set a config setting, you can use `Hoardable.with`:
|
243
251
|
|
244
252
|
```ruby
|
@@ -247,17 +255,26 @@ Hoardable.with(enabled: false) do
|
|
247
255
|
end
|
248
256
|
```
|
249
257
|
|
250
|
-
You can also configure these variables per `ActiveRecord` class as well using `
|
258
|
+
You can also configure these variables per `ActiveRecord` class as well using `hoardable_config`:
|
251
259
|
|
252
260
|
```ruby
|
253
261
|
class Comment < ActiveRecord::Base
|
254
262
|
include Hoardable::Model
|
255
|
-
|
263
|
+
hoardable_config version_updates: false
|
256
264
|
end
|
257
265
|
```
|
258
266
|
|
259
|
-
If
|
260
|
-
|
267
|
+
If you want to temporarily set the `hoardable_config` for a specific model, you can use
|
268
|
+
`with_hoardable_config`:
|
269
|
+
|
270
|
+
```ruby
|
271
|
+
Comment.with_hoardable_config(version_updates: true) do
|
272
|
+
comment.update!(text: "Edited")
|
273
|
+
end
|
274
|
+
```
|
275
|
+
|
276
|
+
If a model-level option exists, it will use that. Otherwise, it will fall back to the global
|
277
|
+
`Hoardable` config.
|
261
278
|
|
262
279
|
### Relationships
|
263
280
|
|
@@ -267,17 +284,20 @@ features in this area, but here are a couple pointers.
|
|
267
284
|
Sometimes you’ll have a record that belongs to a record that you’ll trash. Now the child record’s
|
268
285
|
foreign key will point to the non-existent trashed version of the parent. If you would like this
|
269
286
|
`belongs_to` relationship to always resolve to the parent as if it was not trashed, you can include
|
270
|
-
the scope on the relationship definition:
|
287
|
+
the `include_versions` scope on the relationship definition:
|
271
288
|
|
272
289
|
```ruby
|
273
|
-
|
290
|
+
class Comment
|
291
|
+
include Hoardable::Model
|
292
|
+
belongs_to :post, -> { include_versions } # `Post` also includes `Hoardable::Model`
|
293
|
+
end
|
274
294
|
```
|
275
295
|
|
276
296
|
Sometimes you’ll trash something that `has_many :children, dependent: :destroy` and both the parent
|
277
297
|
and child model classes include `Hoardable::Model`. Whenever a hoardable version is created in a
|
278
298
|
database transaction, it will create or re-use a unique event UUID for that transaction and tag all
|
279
|
-
versions created with it. That way, when you `untrash!` a
|
280
|
-
|
299
|
+
versions created with it. That way, when you `untrash!` a record, you can find and `untrash!`
|
300
|
+
records that were trashed with it:
|
281
301
|
|
282
302
|
```ruby
|
283
303
|
class Post < ActiveRecord::Base
|
@@ -295,20 +315,35 @@ class Post < ActiveRecord::Base
|
|
295
315
|
end
|
296
316
|
```
|
297
317
|
|
318
|
+
If there are models that might be related to versions that are trashed or otherwise, and/or might
|
319
|
+
trashed themselves, you can bypass the inherited tables query handling altogether by using the
|
320
|
+
`return_everything` configuration variable in `Hoardable.with`:
|
321
|
+
|
322
|
+
```ruby
|
323
|
+
post.destroy!
|
324
|
+
|
325
|
+
Hoardable.with(return_everything: true) do
|
326
|
+
post = Post.find(post.id) # returns the trashed post as if it was not
|
327
|
+
post.comments # returns the trashed comments as well
|
328
|
+
end
|
329
|
+
|
330
|
+
post.reload # raises ActiveRecord::RecordNotFound
|
331
|
+
```
|
332
|
+
|
298
333
|
## Gem Comparison
|
299
334
|
|
300
|
-
###
|
335
|
+
### [`paper_trail`](https://github.com/paper-trail-gem/paper_trail)
|
301
336
|
|
302
337
|
`paper_trail` is maybe the most popular and fully featured gem in this space. It works for other
|
303
|
-
|
304
|
-
|
305
|
-
|
306
|
-
|
307
|
-
|
308
|
-
|
309
|
-
|
310
|
-
|
311
|
-
|
338
|
+
database types than PostgeSQL and (by default) stores all versions of all versioned models in a
|
339
|
+
single `versions` table. It stores changes in a `text`, `json`, or `jsonb` column. In order to
|
340
|
+
efficiently query the `versions` table, a `jsonb` column should be used, which takes up a lot of
|
341
|
+
space to index. Unless you customize your configuration, all `versions` for all models types are
|
342
|
+
in the same table which is inefficient if you are only interested in querying versions of a single
|
343
|
+
model. By contrast, `hoardable` stores versions in smaller, isolated and inherited tables with the
|
344
|
+
same database columns as their parents, which are more efficient for querying as well as auditing
|
345
|
+
for truncating and dropping. The concept of a `temporal` time-frame does not exist for a single
|
346
|
+
version since there is only a `created_at` timestamp.
|
312
347
|
|
313
348
|
### [`audited`](https://github.com/collectiveidea/audited)
|
314
349
|
|
data/lib/hoardable/hoardable.rb
CHANGED
@@ -7,7 +7,7 @@ module Hoardable
|
|
7
7
|
DATA_KEYS = %i[meta whodunit note event_uuid].freeze
|
8
8
|
# Symbols for use with setting {Hoardable} configuration. See {file:README.md#configuration
|
9
9
|
# README} for more.
|
10
|
-
CONFIG_KEYS = %i[enabled version_updates save_trash].freeze
|
10
|
+
CONFIG_KEYS = %i[enabled version_updates save_trash return_everything].freeze
|
11
11
|
|
12
12
|
# @!visibility private
|
13
13
|
VERSION_CLASS_SUFFIX = 'Version'
|
@@ -20,7 +20,7 @@ module Hoardable
|
|
20
20
|
|
21
21
|
@context = {}
|
22
22
|
@config = CONFIG_KEYS.to_h do |key|
|
23
|
-
[key,
|
23
|
+
[key, key != :return_everything]
|
24
24
|
end
|
25
25
|
|
26
26
|
class << self
|
@@ -46,7 +46,7 @@ module Hoardable
|
|
46
46
|
|
47
47
|
# This is a general use method for setting {DATA_KEYS} or {CONFIG_KEYS} around a scoped block.
|
48
48
|
#
|
49
|
-
# @param hash [Hash]
|
49
|
+
# @param hash [Hash] config and contextual data to set within a block
|
50
50
|
def with(hash)
|
51
51
|
current_config = @config
|
52
52
|
current_context = @context
|
data/lib/hoardable/model.rb
CHANGED
@@ -10,7 +10,7 @@ module Hoardable
|
|
10
10
|
|
11
11
|
class_methods do
|
12
12
|
# @!visibility private
|
13
|
-
attr_reader :
|
13
|
+
attr_reader :_hoardable_config
|
14
14
|
|
15
15
|
# If called with a hash, this will set the model-level +Hoardable+ configuration variables. If
|
16
16
|
# called without an argument it will return the computed +Hoardable+ configuration considering
|
@@ -19,16 +19,29 @@ module Hoardable
|
|
19
19
|
# @param hash [Hash] The +Hoardable+ configuration for the model. Keys must be present in
|
20
20
|
# {CONFIG_KEYS}
|
21
21
|
# @return [Hash]
|
22
|
-
def
|
22
|
+
def hoardable_config(hash = nil)
|
23
23
|
if hash
|
24
|
-
@
|
24
|
+
@_hoardable_config = hash.slice(*Hoardable::CONFIG_KEYS)
|
25
25
|
else
|
26
|
-
@
|
26
|
+
@_hoardable_config ||= {}
|
27
27
|
Hoardable::CONFIG_KEYS.to_h do |key|
|
28
|
-
[key,
|
28
|
+
[key, @_hoardable_config.key?(key) ? @_hoardable_config[key] : Hoardable.send(key)]
|
29
29
|
end
|
30
30
|
end
|
31
31
|
end
|
32
|
+
|
33
|
+
# Set the model-level +Hoardable+ configuration variables around a block. The configuration
|
34
|
+
# will be reset to it’s previous value afterwards.
|
35
|
+
#
|
36
|
+
# @param hash [Hash] The +Hoardable+ configuration for the model. Keys must be present in
|
37
|
+
# {CONFIG_KEYS}
|
38
|
+
def with_hoardable_config(hash)
|
39
|
+
current_config = @_hoardable_config
|
40
|
+
@_hoardable_config = hash.slice(*Hoardable::CONFIG_KEYS)
|
41
|
+
yield
|
42
|
+
ensure
|
43
|
+
@_hoardable_config = current_config
|
44
|
+
end
|
32
45
|
end
|
33
46
|
|
34
47
|
included do
|
@@ -45,7 +45,7 @@ module Hoardable
|
|
45
45
|
#
|
46
46
|
# @return [Boolean]
|
47
47
|
def trashed?
|
48
|
-
versions.trashed.limit(1).order(_during: :desc).first&.
|
48
|
+
versions.trashed.limit(1).order(_during: :desc).first&.id == id
|
49
49
|
end
|
50
50
|
|
51
51
|
# Returns the +version+ at the supplied +datetime+ or +time+. It will return +self+ if there is
|
@@ -71,15 +71,15 @@ module Hoardable
|
|
71
71
|
private
|
72
72
|
|
73
73
|
def hoardable_callbacks_enabled
|
74
|
-
self.class.
|
74
|
+
self.class.hoardable_config[:enabled] && !self.class.name.end_with?(VERSION_CLASS_SUFFIX)
|
75
75
|
end
|
76
76
|
|
77
77
|
def hoardable_save_trash
|
78
|
-
self.class.
|
78
|
+
self.class.hoardable_config[:save_trash]
|
79
79
|
end
|
80
80
|
|
81
81
|
def hoardable_version_updates
|
82
|
-
self.class.
|
82
|
+
self.class.hoardable_config[:version_updates]
|
83
83
|
end
|
84
84
|
|
85
85
|
def insert_hoardable_version_on_update(&block)
|
data/lib/hoardable/tableoid.rb
CHANGED
@@ -17,9 +17,16 @@ module Hoardable
|
|
17
17
|
# @!visibility private
|
18
18
|
attr_writer :tableoid
|
19
19
|
|
20
|
-
# By default
|
21
|
-
#
|
22
|
-
|
20
|
+
# By default {Hoardable} only returns instances of the parent table, and not the +versions+ in
|
21
|
+
# the inherited table. This can be bypassed by using the {.include_versions} scope or wrapping
|
22
|
+
# the code in a `Hoardable.with(return_everything: true)` block.
|
23
|
+
default_scope do
|
24
|
+
if hoardable_config[:return_everything]
|
25
|
+
where(nil)
|
26
|
+
else
|
27
|
+
where(TABLEOID_AREL_CONDITIONS.call(arel_table, :eq))
|
28
|
+
end
|
29
|
+
end
|
23
30
|
|
24
31
|
# @!scope class
|
25
32
|
# @!method include_versions
|
data/lib/hoardable/version.rb
CHANGED
data/sig/hoardable.rbs
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module Hoardable
|
2
2
|
VERSION: String
|
3
3
|
DATA_KEYS: [:meta, :whodunit, :note, :event_uuid]
|
4
|
-
CONFIG_KEYS: [:enabled, :version_updates, :save_trash]
|
4
|
+
CONFIG_KEYS: [:enabled, :version_updates, :save_trash, :return_everything]
|
5
5
|
VERSION_CLASS_SUFFIX: String
|
6
6
|
VERSION_TABLE_SUFFIX: String
|
7
7
|
DURING_QUERY: String
|
@@ -71,8 +71,8 @@ module Hoardable
|
|
71
71
|
include VersionModel
|
72
72
|
include SourceModel
|
73
73
|
|
74
|
-
|
75
|
-
def
|
74
|
+
def hoardable_config: (?nil hash) -> untyped
|
75
|
+
def with_hoardable_config: (untyped hash) -> untyped
|
76
76
|
end
|
77
77
|
|
78
78
|
class MigrationGenerator
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hoardable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- justin talbott
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-08-
|
11
|
+
date: 2022-08-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|