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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: c960d95a373942d9183464cc50b7c4213c25c7563fa9d920c81d2c325ea71705
4
- data.tar.gz: e7e0f289e60acd720538edc15584209ed3d30e08b21758d06884a5486f198ee0
3
+ metadata.gz: 50086ef99aac41454b28ab8bff2e8abf94d7870b371da0c706c477e0b296ffc3
4
+ data.tar.gz: 6e6d4ab40470bbfb93e23e96fdbb2d8b086878d24e55d499ac368523125e5397
5
5
  SHA512:
6
- metadata.gz: a83966223151922d24bb009ac50465723388ba91825e27cf933bb5e00370c270a0518ec828358f1109a040e2a9202cee7b37d7ea98e0387b30dc07a74f7eb851
7
- data.tar.gz: 6bc246f6664b61c5000ffa71b24c8ddd30c409eda87e790b0ea1bd9d47f46c4e85e0b5eb89736939a75018e272cdd5ac2ce1217c7c7e9272ddc4f96cc8cc33f4
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 `hoardable_options`:
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
- hoardable_options version_updates: false
263
+ hoardable_config version_updates: false
256
264
  end
257
265
  ```
258
266
 
259
- If either the model-level option or global option for a configuration variable is set to `false`,
260
- that behavior will be disabled.
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
- belongs_to :parent, -> { include_versions }
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 parent object, you can find and `untrash!`
280
- the children like so:
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
- ### [`paper_trail`](https://github.com/paper-trail-gem/paper_trail)
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
- database types than PostgeSQL and (by default) stores all versions of all versioned models in a
304
- single `versions` table. It stores changes in a `text`, `json`, or `jsonb` column. In order to
305
- efficiently query the `versions` table, a `jsonb` column should be used, which takes up a lot of
306
- space to index. Unless you customize your configuration, all `versions` for all models types are
307
- in the same table which is inefficient if you are only interested in querying versions of a single
308
- model. By contrast, `hoardable` stores versions in smaller, isolated and inherited tables with the
309
- same database columns as their parents, which are more efficient for querying as well as auditing
310
- for truncating and dropping. The concept of a `temporal` time-frame does not exist for a single
311
- version since there is only a `created_at` timestamp.
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
 
@@ -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, true]
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] Options and contextual data to set within a block
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
@@ -10,7 +10,7 @@ module Hoardable
10
10
 
11
11
  class_methods do
12
12
  # @!visibility private
13
- attr_reader :_hoardable_options
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 hoardable_options(hash = nil)
22
+ def hoardable_config(hash = nil)
23
23
  if hash
24
- @_hoardable_options = hash.slice(*Hoardable::CONFIG_KEYS)
24
+ @_hoardable_config = hash.slice(*Hoardable::CONFIG_KEYS)
25
25
  else
26
- @_hoardable_options ||= {}
26
+ @_hoardable_config ||= {}
27
27
  Hoardable::CONFIG_KEYS.to_h do |key|
28
- [key, Hoardable.send(key) != false && @_hoardable_options[key] != false]
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&.send(:hoardable_source_attributes) == attributes
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.hoardable_options[:enabled] && !self.class.name.end_with?(VERSION_CLASS_SUFFIX)
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.hoardable_options[:save_trash]
78
+ self.class.hoardable_config[:save_trash]
79
79
  end
80
80
 
81
81
  def hoardable_version_updates
82
- self.class.hoardable_options[:version_updates]
82
+ self.class.hoardable_config[:version_updates]
83
83
  end
84
84
 
85
85
  def insert_hoardable_version_on_update(&block)
@@ -17,9 +17,16 @@ module Hoardable
17
17
  # @!visibility private
18
18
  attr_writer :tableoid
19
19
 
20
- # By default, {Hoardable} only returns instances of the parent table, and not the +versions+
21
- # in the inherited table.
22
- default_scope { where(TABLEOID_AREL_CONDITIONS.call(arel_table, :eq)) }
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Hoardable
4
- VERSION = '0.2.0'
4
+ VERSION = '0.3.0'
5
5
  end
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
- attr_reader _hoardable_options: Hash[untyped, untyped]
75
- def hoardable_options: (?nil hash) -> untyped
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.2.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-08 00:00:00.000000000 Z
11
+ date: 2022-08-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord