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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ffb14fbf0391e0fb8c91c363740372b0e9688711ed41e620fd1707c690562cb5
4
- data.tar.gz: 60c00ff5bd2266bfebc2411945f4f6b8cb9f1435ef9b012a582fffbf2e10b73c
3
+ metadata.gz: dcfaf7d239a170431fa82d70ab56b18bfb54a327b46376017357368b38f484b3
4
+ data.tar.gz: 833d8fb9ca610983f9a9e510cd6fc94776f043bf3d35ec7e052a2ade87cf1e5a
5
5
  SHA512:
6
- metadata.gz: 729687b8c87777eeb8d2dd923b67917ae9000fe73d604517ecdb2410361d659c437bbe9c491c89927942540edf2fc12cdab8ca51cc7c4e3c9dfd1443e2a2b669
7
- data.tar.gz: 25690387b0d2ec4ee5f951579c038e4cddedbd9f5ba3bf3aaafdfe8eeace856004203ffb940fc5581baf0ee31993168a78502774cb36173e85900bb9428e1ff4
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.3.2...master)
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/Tests/badge.svg" style="max-width:100%;" height='21' style='border:0px;height:21px;' border='0' alt="CI Status"></a>
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
- - Predictible and explicit behaviour provides much needed clarity to your restore logic
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 concious 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.
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 `@readonly = true` attribute set on them. If you want to perform any write actions on the returned instances you will have to set `@readonly = nil`.
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!(legacy_identifier=nil, identifier: nil, user: nil, metadata: nil)
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
- snapshot_items = []
19
+ new_entries = []
26
20
 
27
- snapshot_items << snapshot.build_snapshot_item(self)
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
- snapshot_items << snapshot.build_snapshot_item(child_item, child_group_name: child_group_name)
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.import(snapshot_items, validate: true)
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: instance.attributes,
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
- reified_item.readonly!
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 = "unsafe_load"
23
+ yaml_method = YAML.respond_to?(:unsafe_load) ? :unsafe_load : :load
23
24
 
24
- if !YAML.respond_to?("unsafe_load")
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
 
@@ -1,3 +1,3 @@
1
1
  module ActiveSnapshot
2
- VERSION = "0.3.2".freeze
2
+ VERSION = "0.5.0".freeze
3
3
  end
@@ -3,29 +3,29 @@ require "active_snapshot/config"
3
3
 
4
4
  require 'active_support/lazy_load_hooks'
5
5
 
6
- ActiveSupport.on_load(:active_record) do
7
- require "activerecord-import"
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
- module ActiveSnapshot
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.3.2
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: 2023-10-17 00:00:00.000000000 Z
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.6
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.