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