omg-audit-group 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +12 -0
- data/.rspec +3 -0
- data/README.md +60 -0
- data/audit_group.gemspec +38 -0
- data/lib/audit_group/request.rb +59 -0
- data/lib/audit_group/version.rb +5 -0
- data/lib/audit_group.rb +13 -0
- data/spec/audit_group/request_spec.rb +110 -0
- data/spec/audit_group_spec.rb +44 -0
- data/spec/spec_helper.rb +15 -0
- metadata +96 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 4aefcd1c0eb006272723f7ed68f14cd719e6480d833e9354730ee42340d6b814
|
4
|
+
data.tar.gz: 418949a9ea417499e1ff0566f1255940c273bcc5404311bfd4352eecc34b3196
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ef815f6b87adb3fe2df279b84dd94a7ff48f8075fa2e91292680b270bec764ff1800b38b90523d02c7f5ed92d936fcdc95bf56548a454f4e899ad9e47672f29
|
7
|
+
data.tar.gz: 7ce8a2a142907e59690af0cf912302aed6fe607cefd1b133b43520517a68dd1049845d6ef32155c73c088eaebe7ab4011899e3ed859ec48c8934567f788b2299
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# AuditGroup
|
2
|
+
|
3
|
+
Group ActiveRecord operations together by assigning all of their audits the same `request_uuid`.
|
4
|
+
|
5
|
+
## Requirements
|
6
|
+
|
7
|
+
- [Audited](https://github.com/collectiveidea/audited) gem
|
8
|
+
|
9
|
+
## Installation
|
10
|
+
|
11
|
+
### Testing locally
|
12
|
+
```sh
|
13
|
+
# Build gem
|
14
|
+
gem build audit_group.gemspec
|
15
|
+
|
16
|
+
# Install gem
|
17
|
+
gem i -l /path/to/this/repo/omg-audit_group-0.1.0.gem
|
18
|
+
```
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
For convenience, the following operations are delegated from the `AuditGroup` module to the `AuditGroup::Request` class:
|
23
|
+
|
24
|
+
- `new`
|
25
|
+
- `request`
|
26
|
+
- `current`
|
27
|
+
- `request_uuid`
|
28
|
+
- `audits`
|
29
|
+
|
30
|
+
Here are some use cases:
|
31
|
+
|
32
|
+
```ruby
|
33
|
+
# Group operations under the same request_uuid
|
34
|
+
AuditGroup.request { perform_some_operations }
|
35
|
+
|
36
|
+
# View the last request_uuid (the above also returns it)
|
37
|
+
AuditGroup.request_uuid
|
38
|
+
|
39
|
+
# View the audits from the last request
|
40
|
+
AuditGroup.audits
|
41
|
+
```
|
42
|
+
|
43
|
+
You can also create separate `AuditGroup::Request` objects to reuse.
|
44
|
+
|
45
|
+
```ruby
|
46
|
+
group = AuditGroup.new
|
47
|
+
group.request { perform_some_operations }
|
48
|
+
...
|
49
|
+
group.request { perform_more_operations }
|
50
|
+
group.audits
|
51
|
+
```
|
52
|
+
|
53
|
+
## Running tests
|
54
|
+
|
55
|
+
```ruby
|
56
|
+
rspec
|
57
|
+
|
58
|
+
# or
|
59
|
+
bundle exec rspec
|
60
|
+
```
|
data/audit_group.gemspec
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'lib/audit_group/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |spec|
|
6
|
+
spec.name = 'omg-audit-group'
|
7
|
+
spec.version = AuditGroup::VERSION
|
8
|
+
spec.authors = ['Matthew Greenfield']
|
9
|
+
spec.email = ['mattgreenfield1@gmail.com']
|
10
|
+
|
11
|
+
spec.summary = 'Groups transactions from the `audited` gem into a single request_uuid'
|
12
|
+
spec.description = 'Create, update, and delete records within a block, assign ' \
|
13
|
+
'the same request_uuid to them, and be able to easily view ' \
|
14
|
+
'and undo them'
|
15
|
+
|
16
|
+
spec.homepage = 'https://github.com/omgreenfield/omg-util/tree/main/audit_group'
|
17
|
+
spec.license = 'MIT'
|
18
|
+
spec.required_ruby_version = '>= 2.7.0'
|
19
|
+
|
20
|
+
spec.metadata['homepage_uri'] = spec.homepage
|
21
|
+
spec.metadata['rubygems_mfa_required'] = 'true'
|
22
|
+
|
23
|
+
# Specify which files should be added to the gem when it is released.
|
24
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
25
|
+
spec.files = Dir.chdir(__dir__) do
|
26
|
+
`git ls-files -z`.split("\x0").reject do |f|
|
27
|
+
(File.expand_path(f) == __FILE__) ||
|
28
|
+
f.start_with?(*%w[spec/.git .github Gemfile])
|
29
|
+
end
|
30
|
+
end
|
31
|
+
spec.require_paths = ['lib']
|
32
|
+
|
33
|
+
spec.add_dependency 'activesupport', '>= 6.0', '< 8.0'
|
34
|
+
spec.add_dependency 'audited', '>= 4.9', '< 6.0'
|
35
|
+
|
36
|
+
# For more information and examples about making a new gem, check out our
|
37
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
38
|
+
end
|
@@ -0,0 +1,59 @@
|
|
1
|
+
require 'active_support/all'
|
2
|
+
require 'audited'
|
3
|
+
require 'pry-byebug'
|
4
|
+
|
5
|
+
module AuditGroup
|
6
|
+
class Request
|
7
|
+
attr_reader :block, :request_uuid
|
8
|
+
|
9
|
+
delegate :current, :unset_request_uuid, to: :class
|
10
|
+
|
11
|
+
class << self
|
12
|
+
delegate :request_uuid, :audits, to: :current
|
13
|
+
|
14
|
+
attr_accessor :current
|
15
|
+
|
16
|
+
def set_request_uuid(request_uuid = SecureRandom.uuid)
|
17
|
+
Audited.store[:current_request_uuid] = request_uuid
|
18
|
+
end
|
19
|
+
|
20
|
+
def unset_request_uuid
|
21
|
+
Audited.store.delete(:current_request_uuid)
|
22
|
+
end
|
23
|
+
|
24
|
+
def reset
|
25
|
+
unset_request_uuid
|
26
|
+
@current = nil
|
27
|
+
end
|
28
|
+
|
29
|
+
def request(&block)
|
30
|
+
raise ArgumentError, 'No block given and no active group' unless block_given?
|
31
|
+
|
32
|
+
new.request(&block)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def initialize(request_uuid = SecureRandom.uuid)
|
37
|
+
@request_uuid = request_uuid
|
38
|
+
self.class.current = self
|
39
|
+
end
|
40
|
+
|
41
|
+
def request(&block)
|
42
|
+
set_request_uuid
|
43
|
+
|
44
|
+
block.call if block.present?
|
45
|
+
|
46
|
+
self
|
47
|
+
ensure
|
48
|
+
unset_request_uuid
|
49
|
+
end
|
50
|
+
|
51
|
+
def set_request_uuid
|
52
|
+
self.class.set_request_uuid(request_uuid)
|
53
|
+
end
|
54
|
+
|
55
|
+
def audits
|
56
|
+
Audited::Audit.where(request_uuid: request_uuid)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
data/lib/audit_group.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative 'audit_group/request'
|
4
|
+
require_relative 'audit_group/version'
|
5
|
+
|
6
|
+
require 'active_support/all'
|
7
|
+
require 'audited'
|
8
|
+
|
9
|
+
module AuditGroup
|
10
|
+
class << self
|
11
|
+
delegate :new, :request, :current, :request_uuid, :audits, to: Request
|
12
|
+
end
|
13
|
+
end
|
@@ -0,0 +1,110 @@
|
|
1
|
+
require 'audit_group/request'
|
2
|
+
|
3
|
+
RSpec.describe AuditGroup::Request do
|
4
|
+
describe 'class methods' do
|
5
|
+
describe '.current' do
|
6
|
+
it 'returns the last request created' do
|
7
|
+
request = described_class.request {}
|
8
|
+
expect(described_class.current).to eq(request)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
describe '.set_request_uuid' do
|
13
|
+
it "sets the Audit store's current_request_uuid" do
|
14
|
+
described_class.set_request_uuid('123')
|
15
|
+
expect(Audited.store[:current_request_uuid]).to eq('123')
|
16
|
+
|
17
|
+
described_class.set_request_uuid
|
18
|
+
expect(Audited.store[:current_request_uuid]).to match(/\A\h{8}-\h{4}-\h{4}-\h{4}-\h{12}\z/)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.unset_request_uuid' do
|
23
|
+
it "resets the Audit store's current_request_uuid" do
|
24
|
+
Audited.store[:current_request_uuid] = '123'
|
25
|
+
described_class.unset_request_uuid
|
26
|
+
expect(Audited.store[:current_request_uuid]).to be_nil
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '.reset' do
|
31
|
+
it 'unsets the request_uuid and current request' do
|
32
|
+
described_class.set_request_uuid('123')
|
33
|
+
described_class.current = 'some request'
|
34
|
+
|
35
|
+
expect(Audited.store[:current_request_uuid]).to eq('123')
|
36
|
+
expect(described_class.current).to eq('some request')
|
37
|
+
|
38
|
+
described_class.reset
|
39
|
+
|
40
|
+
expect(Audited.store[:current_request_uuid]).to be_nil
|
41
|
+
expect(described_class.current).to be_nil
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
describe '.request' do
|
46
|
+
it 'raises an ArgumentError if no block is given and no active group' do
|
47
|
+
expect { described_class.request }.to raise_error(ArgumentError, 'No block given and no active group')
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'creates a new request if block is given' do
|
51
|
+
expect { |block| described_class.request(&block) }.to yield_control
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
describe '.request_uuid' do
|
56
|
+
it 'delegates to current' do
|
57
|
+
described_class.request {}
|
58
|
+
expect(described_class.request_uuid).to eq(described_class.current.request_uuid)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '.audits' do
|
63
|
+
it 'delegates to current' do
|
64
|
+
described_class.new('123')
|
65
|
+
audited_audit = class_double('Audited::Audit').as_stubbed_const
|
66
|
+
expect(audited_audit).to receive(:where).with(request_uuid: '123').and_return('some audits')
|
67
|
+
expect(described_class.audits).to eq('some audits')
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe 'instance methods' do
|
73
|
+
describe '#initialize' do
|
74
|
+
it 'sets the request_uuid and current request' do
|
75
|
+
request = described_class.new('123')
|
76
|
+
expect(request.request_uuid).to eq('123')
|
77
|
+
expect(described_class.current).to eq(request)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
describe '#request' do
|
82
|
+
it 'sets the current_request_uuid, calls the block, then resets current_request_uuid' do
|
83
|
+
request = described_class.new('123')
|
84
|
+
|
85
|
+
request.request do
|
86
|
+
expect(Audited.store[:current_request_uuid]).to eq('123')
|
87
|
+
end
|
88
|
+
|
89
|
+
expect(Audited.store[:current_request_uuid]).to be_nil
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
describe '#set_request_uuid' do
|
94
|
+
it 'delegates to class' do
|
95
|
+
request = described_class.new('123')
|
96
|
+
expect(request).to receive(:set_request_uuid)
|
97
|
+
request.set_request_uuid
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
describe '#audits' do
|
102
|
+
it 'returns audits with request_uuid' do
|
103
|
+
request = described_class.new('123')
|
104
|
+
audited_audit = class_double('Audited::Audit').as_stubbed_const
|
105
|
+
expect(audited_audit).to receive(:where).with(request_uuid: '123').and_return('some audits')
|
106
|
+
expect(request.audits).to eq('some audits')
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
RSpec.describe AuditGroup do
|
4
|
+
it 'has a version number' do
|
5
|
+
expect(AuditGroup::VERSION).not_to be_nil
|
6
|
+
end
|
7
|
+
|
8
|
+
describe '.new' do
|
9
|
+
it 'delegates to Request' do
|
10
|
+
expect(AuditGroup.new).to be_a(AuditGroup::Request)
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
describe '.request' do
|
15
|
+
it 'creates a new Request' do
|
16
|
+
request = AuditGroup.request { puts 'Hi, Mom!' }
|
17
|
+
|
18
|
+
expect(request).to be_a(AuditGroup::Request)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
describe '.current' do
|
23
|
+
it 'returns the last created Request object' do
|
24
|
+
request = AuditGroup.request { puts 'Hi, Dad!' }
|
25
|
+
expect(AuditGroup.current).to eq(request)
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
describe '.request_uuid' do
|
30
|
+
it 'returns the current request_uuid' do
|
31
|
+
request = AuditGroup.request { puts 'Hi, Steve!' }
|
32
|
+
expect(AuditGroup.request_uuid).to eq(request.request_uuid)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
describe '.audits' do
|
37
|
+
it 'delegates to Request' do
|
38
|
+
AuditGroup.request { puts "Who's Steve?" }
|
39
|
+
audited_audit = class_double('Audited::Audit').as_stubbed_const
|
40
|
+
expect(audited_audit).to receive(:where).with(request_uuid: an_instance_of(String)).and_return('some audits')
|
41
|
+
expect(AuditGroup.audits).to eq('some audits')
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "audit_group"
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
# Enable flags like --only-failures and --next-failure
|
7
|
+
config.example_status_persistence_file_path = ".rspec_status"
|
8
|
+
|
9
|
+
# Disable RSpec exposing methods globally on `Module` and `main`
|
10
|
+
config.disable_monkey_patching!
|
11
|
+
|
12
|
+
config.expect_with :rspec do |c|
|
13
|
+
c.syntax = :expect
|
14
|
+
end
|
15
|
+
end
|
metadata
ADDED
@@ -0,0 +1,96 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: omg-audit-group
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Matthew Greenfield
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2024-04-19 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: activesupport
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '6.0'
|
20
|
+
- - "<"
|
21
|
+
- !ruby/object:Gem::Version
|
22
|
+
version: '8.0'
|
23
|
+
type: :runtime
|
24
|
+
prerelease: false
|
25
|
+
version_requirements: !ruby/object:Gem::Requirement
|
26
|
+
requirements:
|
27
|
+
- - ">="
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '6.0'
|
30
|
+
- - "<"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '8.0'
|
33
|
+
- !ruby/object:Gem::Dependency
|
34
|
+
name: audited
|
35
|
+
requirement: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '4.9'
|
40
|
+
- - "<"
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
version: '6.0'
|
43
|
+
type: :runtime
|
44
|
+
prerelease: false
|
45
|
+
version_requirements: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: '4.9'
|
50
|
+
- - "<"
|
51
|
+
- !ruby/object:Gem::Version
|
52
|
+
version: '6.0'
|
53
|
+
description: Create, update, and delete records within a block, assign the same request_uuid
|
54
|
+
to them, and be able to easily view and undo them
|
55
|
+
email:
|
56
|
+
- mattgreenfield1@gmail.com
|
57
|
+
executables: []
|
58
|
+
extensions: []
|
59
|
+
extra_rdoc_files: []
|
60
|
+
files:
|
61
|
+
- ".gitignore"
|
62
|
+
- ".rspec"
|
63
|
+
- README.md
|
64
|
+
- audit_group.gemspec
|
65
|
+
- lib/audit_group.rb
|
66
|
+
- lib/audit_group/request.rb
|
67
|
+
- lib/audit_group/version.rb
|
68
|
+
- spec/audit_group/request_spec.rb
|
69
|
+
- spec/audit_group_spec.rb
|
70
|
+
- spec/spec_helper.rb
|
71
|
+
homepage: https://github.com/omgreenfield/omg-util/tree/main/audit_group
|
72
|
+
licenses:
|
73
|
+
- MIT
|
74
|
+
metadata:
|
75
|
+
homepage_uri: https://github.com/omgreenfield/omg-util/tree/main/audit_group
|
76
|
+
rubygems_mfa_required: 'true'
|
77
|
+
post_install_message:
|
78
|
+
rdoc_options: []
|
79
|
+
require_paths:
|
80
|
+
- lib
|
81
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: 2.7.0
|
86
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: '0'
|
91
|
+
requirements: []
|
92
|
+
rubygems_version: 3.5.9
|
93
|
+
signing_key:
|
94
|
+
specification_version: 4
|
95
|
+
summary: Groups transactions from the `audited` gem into a single request_uuid
|
96
|
+
test_files: []
|