active_snapshot 0.3.2 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -1
- data/README.md +16 -14
- data/lib/active_snapshot/models/concerns/snapshots_concern.rb +9 -13
- data/lib/active_snapshot/models/snapshot.rb +12 -3
- data/lib/active_snapshot/models/snapshot_item.rb +6 -7
- data/lib/active_snapshot/version.rb +1 -1
- data/lib/active_snapshot.rb +13 -13
- metadata +5 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: dcfaf7d239a170431fa82d70ab56b18bfb54a327b46376017357368b38f484b3
|
4
|
+
data.tar.gz: 833d8fb9ca610983f9a9e510cd6fc94776f043bf3d35ec7e052a2ade87cf1e5a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a412ace11cbeee26528d5e3b58116a1b716f415ab4c1aead7978e6c5f2ccd1db49ee7c08ea0120226d1f66d1d099384cd6cadec5353a3f2fa5aee28d32b825e8
|
7
|
+
data.tar.gz: 5290672baca7ed50d67e9654acb85851e997f9c601d6fa6aae898cf51ba448686595e30b61c4819eafe6f81608850777a9b75ca5a995c18f9f6b6d8047542bf8
|
data/CHANGELOG.md
CHANGED
@@ -2,9 +2,22 @@ CHANGELOG
|
|
2
2
|
---------
|
3
3
|
|
4
4
|
- **Unreleased**
|
5
|
-
* [View Diff](https://github.com/westonganger/active_snapshot/compare/v0.
|
5
|
+
* [View Diff](https://github.com/westonganger/active_snapshot/compare/v0.5.0...master)
|
6
6
|
* Nothing yet
|
7
7
|
|
8
|
+
- **v0.5.0** - Nov 8, 2024
|
9
|
+
* [View Diff](https://github.com/westonganger/active_snapshot/compare/v0.4.0...v0.5.0)
|
10
|
+
* [#61](https://github.com/westonganger/active_snapshot/pull/61) - Ensure snapshot record returned by `create_snapshot!` is `valid?`
|
11
|
+
* [#60](https://github.com/westonganger/active_snapshot/pull/60) - Store enum value as integer
|
12
|
+
* [#56](https://github.com/westonganger/active_snapshot/pull/56) - Add presence validation for object in SnapshotItem model
|
13
|
+
* [#57](https://github.com/westonganger/active_snapshot/pull/57) - Add readonly argument to `Shapshot#fetch_reified_items`
|
14
|
+
* [#53](https://github.com/westonganger/active_snapshot/pull/53) - Allow `ActiveSnapshot.config` to be called before ActiveRecord `on_load` hook has occurred
|
15
|
+
* [#52](https://github.com/westonganger/active_snapshot/pull/52) - Remove deprecated positional argument on `create_snapshot!`
|
16
|
+
|
17
|
+
- **v0.4.0** - July 23, 2024
|
18
|
+
* [View Diff](https://github.com/westonganger/active_snapshot/compare/v0.3.2...v0.4.0)
|
19
|
+
* [#44](https://github.com/westonganger/active_snapshot/pull/44) - Remove dependency on `activerecord-import` with vanilla ActiveRecord `upsert_all`
|
20
|
+
|
8
21
|
- **v0.3.2** - Oct 17, 2023
|
9
22
|
* [View Diff](https://github.com/westonganger/active_snapshot/compare/v0.3.1...v0.3.2)
|
10
23
|
* [#43](https://github.com/westonganger/active_snapshot/pull/43) - Fix unique index error in generated DB migration
|
data/README.md
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
# ActiveSnapshot
|
2
2
|
|
3
3
|
<a href="https://badge.fury.io/rb/active_snapshot" target="_blank"><img height="21" style='border:0px;height:21px;' border='0' src="https://badge.fury.io/rb/active_snapshot.svg" alt="Gem Version"></a>
|
4
|
-
<a href='https://github.com/westonganger/active_snapshot/actions' target='_blank'><img src="https://github.com/westonganger/active_snapshot/workflows/
|
4
|
+
<a href='https://github.com/westonganger/active_snapshot/actions' target='_blank'><img src="https://github.com/westonganger/active_snapshot/actions/workflows/test.yml/badge.svg?branch=master" style="max-width:100%;" height='21' style='border:0px;height:21px;' border='0' alt="CI Status"></a>
|
5
5
|
<a href='https://rubygems.org/gems/active_snapshot' target='_blank'><img height='21' style='border:0px;height:21px;' src='https://img.shields.io/gem/dt/active_snapshot?color=brightgreen&label=Rubygems%20Downloads' border='0' alt='RubyGems Downloads' /></a>
|
6
6
|
|
7
7
|
Simplified snapshots and restoration for ActiveRecord models and associations with a transparent white-box implementation.
|
@@ -9,15 +9,15 @@ Simplified snapshots and restoration for ActiveRecord models and associations wi
|
|
9
9
|
Key Features:
|
10
10
|
|
11
11
|
- Create and Restore snapshots of a parent record and any specified child records
|
12
|
-
-
|
12
|
+
- Predictable and explicit behaviour provides much needed clarity to your restore logic
|
13
13
|
- Snapshots are created upon request only, we do not use any callbacks
|
14
14
|
- Tiny method footprint so its easy to completely override the logic later
|
15
15
|
|
16
16
|
Why This Library:
|
17
17
|
|
18
|
-
Model Versioning and Restoration require
|
18
|
+
Model Versioning and Restoration require conscious thought, design, and understanding. You should understand your versioning and restoration process completely. This gem's small API and fully understandable design fully supports this.
|
19
19
|
|
20
|
-
I do not recommend using paper_trail-association_tracking because it is mostly a blackbox solution which encourages you to set it up and then assume its Just Working<sup>TM</sup>. This makes for major data problems later. Dont fall into this trap. Instead read this gems brief source code completely before use OR copy the code straight into your codebase. Once you know it, then you are free.
|
20
|
+
I do not recommend using [paper_trail-association_tracking](https://github.com/westonganger/paper_trail-association_tracking) because it is mostly a blackbox solution which encourages you to set it up and then assume its Just Working<sup>TM</sup>. This makes for major data problems later. Dont fall into this trap. Instead read this gems brief source code completely before use OR copy the code straight into your codebase. Once you know it, then you are free.
|
21
21
|
|
22
22
|
|
23
23
|
|
@@ -101,24 +101,24 @@ snapshot.destroy!
|
|
101
101
|
```ruby
|
102
102
|
class Post < ActiveRecord::Base
|
103
103
|
include ActiveSnapshot
|
104
|
-
|
104
|
+
|
105
105
|
has_snapshot_children do
|
106
106
|
### Executed in the context of the instance / self
|
107
107
|
|
108
108
|
### Reload record from database to ensure a clean state and eager load the specified associations
|
109
109
|
instance = self.class.includes(:tags, :ip_address, comments: [:comment_sub_records]).find(id)
|
110
|
-
|
110
|
+
|
111
111
|
### Define the associated records that will be restored
|
112
112
|
{
|
113
113
|
comments: instance.comments,
|
114
|
-
|
114
|
+
|
115
115
|
### Nested Associations can be handled by simply mapping them into an array
|
116
|
-
comment_sub_records: instance.comments.flat_map{|x| x.comment_sub_records },
|
117
|
-
|
116
|
+
comment_sub_records: instance.comments.flat_map{|x| x.comment_sub_records },
|
117
|
+
|
118
118
|
tags: {
|
119
119
|
records: instance.tags
|
120
120
|
},
|
121
|
-
|
121
|
+
|
122
122
|
ip_address: {
|
123
123
|
record: instance.ip_address,
|
124
124
|
delete_method: ->(item){ item.release! }
|
@@ -133,18 +133,20 @@ Now when you run `create_snapshot!` the associations will be tracked accordingly
|
|
133
133
|
|
134
134
|
# Reifying Snapshot Items
|
135
135
|
|
136
|
-
You can view all of the reified snapshot items by calling the following method. Its completely up to you on how to use this data.
|
136
|
+
You can view all of the reified snapshot items by calling the following method. Its completely up to you on how to use this data.
|
137
137
|
|
138
138
|
```ruby
|
139
139
|
reified_parent, reified_children_hash = snapshot.fetch_reified_items
|
140
140
|
```
|
141
141
|
|
142
|
-
As a safety these records have the
|
142
|
+
As a safety these records have the `readonly` attribute set on them.
|
143
|
+
If you want to perform any write actions on the returned instances you will have to set the `readonly` attribute to `false`
|
143
144
|
|
144
145
|
```ruby
|
146
|
+
reified_parent, reified_children_hash = snapshot.fetch_reified_items(readonly: false)
|
147
|
+
# or
|
145
148
|
reified_parent, reified_children_hash = snapshot.fetch_reified_items
|
146
|
-
|
147
|
-
reified_parent.instance_variable_set("@readonly", false)
|
149
|
+
reified_children_hash.first.instance_variable_set("@readonly", false)
|
148
150
|
```
|
149
151
|
|
150
152
|
# Key Models Provided & Additional Customizations
|
@@ -8,13 +8,7 @@ module ActiveSnapshot
|
|
8
8
|
has_many :snapshot_items, as: :item, class_name: 'ActiveSnapshot::SnapshotItem'
|
9
9
|
end
|
10
10
|
|
11
|
-
def create_snapshot!(
|
12
|
-
if identifier.nil? && legacy_identifier
|
13
|
-
identifier = legacy_identifier
|
14
|
-
|
15
|
-
ActiveSupport::Deprecation.warn(LEGACY_POSITIONAL_ARGUMENT_WARNING)
|
16
|
-
end
|
17
|
-
|
11
|
+
def create_snapshot!(identifier: nil, user: nil, metadata: nil)
|
18
12
|
snapshot = snapshots.create!({
|
19
13
|
identifier: identifier,
|
20
14
|
user_id: (user.id if user),
|
@@ -22,21 +16,25 @@ module ActiveSnapshot
|
|
22
16
|
metadata: (metadata || {}),
|
23
17
|
})
|
24
18
|
|
25
|
-
|
19
|
+
new_entries = []
|
26
20
|
|
27
|
-
|
21
|
+
current_time = Time.now
|
22
|
+
|
23
|
+
new_entries << snapshot.build_snapshot_item(self).attributes.merge(created_at: current_time)
|
28
24
|
|
29
25
|
snapshot_children = self.children_to_snapshot
|
30
26
|
|
31
27
|
if snapshot_children
|
32
28
|
snapshot_children.each do |child_group_name, h|
|
33
29
|
h[:records].each do |child_item|
|
34
|
-
|
30
|
+
new_entries << snapshot.build_snapshot_item(child_item, child_group_name: child_group_name).attributes.merge(created_at: current_time)
|
35
31
|
end
|
36
32
|
end
|
37
33
|
end
|
38
34
|
|
39
|
-
SnapshotItem.
|
35
|
+
SnapshotItem.upsert_all(new_entries.map{|x| x.delete("id"); x }, returning: false)
|
36
|
+
|
37
|
+
snapshot.snapshot_items.reset # clear the association cache otherwise snapshot.valid? returns false
|
40
38
|
|
41
39
|
snapshot
|
42
40
|
end
|
@@ -125,7 +123,5 @@ module ActiveSnapshot
|
|
125
123
|
end
|
126
124
|
end
|
127
125
|
|
128
|
-
LEGACY_POSITIONAL_ARGUMENT_WARNING = "Supplying the snapshots :identifier as a positional argument is now deprecated and will be removed in upcoming versions. Please supply the snapshot identifier using the :identifier keyword argument instead.".freeze
|
129
|
-
|
130
126
|
end
|
131
127
|
end
|
@@ -46,8 +46,15 @@ module ActiveSnapshot
|
|
46
46
|
end
|
47
47
|
|
48
48
|
def build_snapshot_item(instance, child_group_name: nil)
|
49
|
+
attributes = instance.attributes
|
50
|
+
attributes.each do |k, v|
|
51
|
+
if instance.class.defined_enums.key?(k)
|
52
|
+
attributes[k] = instance.class.defined_enums.fetch(k).fetch(v)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
49
56
|
self.snapshot_items.new({
|
50
|
-
object:
|
57
|
+
object: attributes,
|
51
58
|
item_id: instance.id,
|
52
59
|
item_type: instance.class.name,
|
53
60
|
child_group_name: child_group_name,
|
@@ -96,7 +103,7 @@ module ActiveSnapshot
|
|
96
103
|
return true
|
97
104
|
end
|
98
105
|
|
99
|
-
def fetch_reified_items
|
106
|
+
def fetch_reified_items(readonly: true)
|
100
107
|
reified_children_hash = {}.with_indifferent_access
|
101
108
|
|
102
109
|
reified_parent = nil
|
@@ -104,7 +111,9 @@ module ActiveSnapshot
|
|
104
111
|
snapshot_items.each do |si|
|
105
112
|
reified_item = si.item_type.constantize.new(si.object)
|
106
113
|
|
107
|
-
|
114
|
+
if readonly
|
115
|
+
reified_item.readonly!
|
116
|
+
end
|
108
117
|
|
109
118
|
key = si.child_group_name
|
110
119
|
|
@@ -12,22 +12,21 @@ module ActiveSnapshot
|
|
12
12
|
validates :snapshot_id, presence: true
|
13
13
|
validates :item_id, presence: true, uniqueness: { scope: [:snapshot_id, :item_type] }
|
14
14
|
validates :item_type, presence: true
|
15
|
+
validates :object, presence: true
|
15
16
|
|
16
17
|
def object
|
17
18
|
return @object if @object
|
18
19
|
|
19
20
|
if ActiveSnapshot.config.storage_method_json?
|
20
|
-
@object = JSON.parse(self[:object])
|
21
|
+
@object = self[:object] ? JSON.parse(self[:object]) : {}
|
21
22
|
elsif ActiveSnapshot.config.storage_method_yaml?
|
22
|
-
yaml_method =
|
23
|
+
yaml_method = YAML.respond_to?(:unsafe_load) ? :unsafe_load : :load
|
23
24
|
|
24
|
-
|
25
|
-
yaml_method = "load"
|
26
|
-
end
|
27
|
-
|
28
|
-
@object = YAML.send(yaml_method, self[:object])
|
25
|
+
@object = self[:object] ? YAML.public_send(yaml_method, self[:object]) : {}
|
29
26
|
elsif ActiveSnapshot.config.storage_method_native_json?
|
30
27
|
@object = self[:object]
|
28
|
+
else
|
29
|
+
raise StandardError, "Unsupported storage_method: `#{ActiveSnapshot.config.storage_method}`"
|
31
30
|
end
|
32
31
|
end
|
33
32
|
|
data/lib/active_snapshot.rb
CHANGED
@@ -3,29 +3,29 @@ require "active_snapshot/config"
|
|
3
3
|
|
4
4
|
require 'active_support/lazy_load_hooks'
|
5
5
|
|
6
|
-
|
7
|
-
|
6
|
+
module ActiveSnapshot
|
7
|
+
@@config = ActiveSnapshot::Config.new
|
8
|
+
|
9
|
+
def self.config(&block)
|
10
|
+
if block_given?
|
11
|
+
block.call(@@config)
|
12
|
+
else
|
13
|
+
return @@config
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
8
17
|
|
18
|
+
ActiveSupport.on_load(:active_record) do
|
9
19
|
require "active_snapshot/models/snapshot"
|
10
20
|
require "active_snapshot/models/snapshot_item"
|
11
21
|
|
12
22
|
require "active_snapshot/models/concerns/snapshots_concern"
|
13
23
|
|
14
|
-
|
24
|
+
ActiveSnapshot.module_eval do
|
15
25
|
extend ActiveSupport::Concern
|
16
26
|
|
17
27
|
included do
|
18
28
|
include ActiveSnapshot::SnapshotsConcern
|
19
29
|
end
|
20
|
-
|
21
|
-
@@config = ActiveSnapshot::Config.new
|
22
|
-
|
23
|
-
def self.config(&block)
|
24
|
-
if block_given?
|
25
|
-
block.call(@@config)
|
26
|
-
else
|
27
|
-
return @@config
|
28
|
-
end
|
29
|
-
end
|
30
30
|
end
|
31
31
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_snapshot
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Weston Ganger
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-11-08 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,14 +16,14 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
19
|
+
version: '6.0'
|
20
20
|
type: :runtime
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
26
|
+
version: '6.0'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: railties
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
@@ -38,20 +38,6 @@ dependencies:
|
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
|
-
- !ruby/object:Gem::Dependency
|
42
|
-
name: activerecord-import
|
43
|
-
requirement: !ruby/object:Gem::Requirement
|
44
|
-
requirements:
|
45
|
-
- - ">="
|
46
|
-
- !ruby/object:Gem::Version
|
47
|
-
version: '0'
|
48
|
-
type: :runtime
|
49
|
-
prerelease: false
|
50
|
-
version_requirements: !ruby/object:Gem::Requirement
|
51
|
-
requirements:
|
52
|
-
- - ">="
|
53
|
-
- !ruby/object:Gem::Version
|
54
|
-
version: '0'
|
55
41
|
- !ruby/object:Gem::Dependency
|
56
42
|
name: rake
|
57
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -177,7 +163,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
177
163
|
- !ruby/object:Gem::Version
|
178
164
|
version: '0'
|
179
165
|
requirements: []
|
180
|
-
rubygems_version: 3.4.
|
166
|
+
rubygems_version: 3.4.22
|
181
167
|
signing_key:
|
182
168
|
specification_version: 4
|
183
169
|
summary: Dead simple snapshot versioning for ActiveRecord models and associations.
|