custom_active_record_observer 0.2.0 → 0.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +5 -5
- data/README.md +86 -12
- data/lib/custom_active_record_observer.rb +36 -0
- data/lib/custom_active_record_observer/all.rb +2 -0
- data/lib/custom_active_record_observer/changes_tracker.rb +1 -1
- data/lib/custom_active_record_observer/dsl.rb +51 -4
- data/lib/custom_active_record_observer/not_nil.rb +4 -0
- data/lib/custom_active_record_observer/observable.rb +9 -3
- data/lib/custom_active_record_observer/observable/base.rb +16 -0
- data/lib/custom_active_record_observer/observable/paranoid.rb +16 -0
- data/lib/custom_active_record_observer/schema.rb +4 -0
- data/lib/custom_active_record_observer/version.rb +1 -1
- metadata +38 -20
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 6644843d956acabec36f996af2a3add3756ee78aaeb5cf1b9286bbf1fb3edfc3
|
4
|
+
data.tar.gz: 6f4f323b250aac555eb294762811fe0c1d52c0f0288d03a41657489c2b804022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 6cc3163d3cf8ba51021ce31681945d301413ee30aff9387014c86c8f522d1cca62331f9ae7d25f910b6020aa06a72ab29956e6302133a48ec1be064df5d48efe
|
7
|
+
data.tar.gz: 30bbcc652985d669ef52e620a9b0e55d136d7feabdffd214b83db4ce1678b33589fe93830dee145d082f8944ec434dc428e7296e597e2fd885511d4927871a34
|
data/README.md
CHANGED
@@ -1,25 +1,99 @@
|
|
1
|
+
[gem]: https://rubygems.org/gems/custom_active_record_observer
|
2
|
+
[travis]: https://travis-ci.org/OnApp/custom_active_record_observer
|
3
|
+
|
1
4
|
# CustomActiveRecordObserver
|
2
5
|
|
3
|
-
|
6
|
+
[][gem]
|
7
|
+
[][travis]
|
8
|
+
|
9
|
+
A DSL to track create/update/destroy operations based on AR callbacks.
|
4
10
|
|
5
|
-
|
11
|
+
### Installation
|
12
|
+
Add the following code to your `Gemfile`
|
6
13
|
|
14
|
+
```ruby
|
15
|
+
# Gemfile
|
16
|
+
gem 'custom_active_record_observer'
|
7
17
|
```
|
8
|
-
|
9
|
-
|
10
|
-
|
18
|
+
and run `bundle install`
|
19
|
+
|
20
|
+
Then add the observation rules (in `config/initializers/events_observation.rb`)
|
21
|
+
```ruby
|
22
|
+
# config/initializers/events_observation.rb
|
23
|
+
CustomActiveRecordObserver.observe 'User' do
|
24
|
+
on_create do |user|
|
25
|
+
# do something
|
11
26
|
end
|
27
|
+
end
|
28
|
+
```
|
29
|
+
|
30
|
+
In this expample we track model `User`. If a new user is created, AR `:after_commit` callback is launched and the block in `on_create` executes.
|
12
31
|
|
13
|
-
|
14
|
-
|
32
|
+
We can track by real classes (which is not always possible, since that code is better to be placed in `config/initializers`). But passing strings or symbols is also allowed:
|
33
|
+
```ruby
|
34
|
+
CustomActiveRecordObserver.observe User, :EngagedUser, 'CompanyOwner' { ... }
|
35
|
+
```
|
36
|
+
Here we track three classes.
|
37
|
+
|
38
|
+
### Usage
|
39
|
+
How do we use `custom_active_record_observer` in the wild? For instance, in this example we publish `UserRegisteredEvent` on user creation. (using `rails_event_store` gem). This is a pretty useful trade-off if there are no operations or aggregates introduced in the system architecture.
|
40
|
+
|
41
|
+
```ruby
|
42
|
+
CustomActiveRecordObserver.observe 'User' do
|
43
|
+
on_create do |user|
|
44
|
+
Rails.application.config.event_store.publish_event(
|
45
|
+
UserRegisteredEvent.strict(data: { user_id: user.id }),
|
46
|
+
stream_name: "users-#{user.id}"
|
47
|
+
)
|
15
48
|
end
|
49
|
+
end
|
50
|
+
```
|
51
|
+
|
52
|
+
#### Usage with `handler`
|
53
|
+
`handler` might be passed into the observation. It is a simple object/class which has metho `call`. The result of `do..end` block is passed into that handler.
|
16
54
|
|
17
|
-
|
18
|
-
|
55
|
+
```ruby
|
56
|
+
handler = ->(event) do
|
57
|
+
Rails.application.config.event_store.publish_event(
|
58
|
+
event,
|
59
|
+
stream_name: "users-#{ event.data.fetch(:user_id) }"
|
60
|
+
)
|
61
|
+
end
|
62
|
+
|
63
|
+
CustomActiveRecordObserver.observe 'User', handler: handler do
|
64
|
+
on_create do |user|
|
65
|
+
UserRegisteredEvent.strict(data: { user_id: user.id })
|
66
|
+
end
|
67
|
+
|
68
|
+
on_add :user_group_id do |user|
|
69
|
+
UserAssignedToUserGroup.strict(data: {
|
70
|
+
user_id: user.id,
|
71
|
+
user_group_id: user.user_group_id
|
72
|
+
})
|
73
|
+
end
|
74
|
+
|
75
|
+
on_change :user_group_id do |user|
|
76
|
+
UserAssignedToAnotherUserGroupEvent.strict(data: {
|
77
|
+
user_id: user.id,
|
78
|
+
user_group_id: user.user_group_id
|
79
|
+
})
|
80
|
+
end
|
81
|
+
|
82
|
+
on_remove :user_group_id do |user|
|
83
|
+
UserUnassignedFromUserGroupEvent.strict(data: {
|
84
|
+
user_id: user.id,
|
85
|
+
user_group_id: user.previous_changes.fetch(:user_group_id).first
|
86
|
+
})
|
87
|
+
end
|
88
|
+
|
89
|
+
on_destroy do |user|
|
90
|
+
UserTerminatedEvent.strict(data: { user_id: user.id })
|
19
91
|
end
|
20
|
-
…
|
21
92
|
end
|
22
93
|
```
|
23
94
|
|
24
|
-
|
25
|
-
|
95
|
+
### Licence
|
96
|
+
See `LICENSE` file.
|
97
|
+
|
98
|
+
## Contributing
|
99
|
+
Bug reports and pull requests are welcome on GitHub at https://github.com/OnApp/custom_active_record_observer.
|
@@ -6,6 +6,42 @@ module CustomActiveRecordObserver
|
|
6
6
|
mattr_accessor :schema
|
7
7
|
@@schema = Schema.new
|
8
8
|
|
9
|
+
# @param class_names [Symbols] - list of class names
|
10
|
+
# may be an object of Class, Symbol, or String
|
11
|
+
# (e.g. :User, 'User' or User)
|
12
|
+
# @example Usage without handler
|
13
|
+
# CustomActiveRecordObserver.observe 'User' do
|
14
|
+
# on_create do |user|
|
15
|
+
# Rails.application.config.event_store.publish_event(
|
16
|
+
# UserRegisteredEvent.strict(data: { user_id: user.id }),
|
17
|
+
# stream_name: "users-#{user.id}"
|
18
|
+
# )
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# on_destroy do |user|
|
22
|
+
# Rails.application.config.event_store.publish_event(
|
23
|
+
# UserTerminatedEvent.strict(data: { user_id: user.id }),
|
24
|
+
# stream_name: "users-#{user.id}"
|
25
|
+
# )
|
26
|
+
# end
|
27
|
+
# end
|
28
|
+
#
|
29
|
+
# @example Usage with handler
|
30
|
+
# handler = ->(event) {
|
31
|
+
# Rails.application.config.event_store.publish_event(
|
32
|
+
# event,
|
33
|
+
# stream_name: "users-#{event.data[:user_id]}"
|
34
|
+
# )
|
35
|
+
# }
|
36
|
+
# CustomActiveRecordObserver.observe 'User', handler: handler do
|
37
|
+
# on_create do |user|
|
38
|
+
# UserRegisteredEvent.strict(data: { user_id: user.id })
|
39
|
+
# end
|
40
|
+
#
|
41
|
+
# on_destroy do |user|
|
42
|
+
# UserTerminatedEvent.strict(data: { user_id: user.id })
|
43
|
+
# end
|
44
|
+
# end
|
9
45
|
def self.observe(*class_names, handler: proc {}, &block)
|
10
46
|
class_names.each do |class_name|
|
11
47
|
DSL.new(block).actions_and_rules.each do |(action, rule)|
|
@@ -5,7 +5,7 @@ module CustomActiveRecordObserver
|
|
5
5
|
method_names.each do |name|
|
6
6
|
define_method name do |*args|
|
7
7
|
@_active_record_observer_changes ||= {}
|
8
|
-
@_active_record_observer_changes.merge!(
|
8
|
+
@_active_record_observer_changes.merge!(previous_changes)
|
9
9
|
|
10
10
|
super(*args)
|
11
11
|
end
|
@@ -1,21 +1,50 @@
|
|
1
|
+
# @title CustomActiveRecordObserver::DSL
|
1
2
|
module CustomActiveRecordObserver
|
3
|
+
# A main methods that are supposed to be used within CustomActiveRecordObserver
|
4
|
+
#
|
5
|
+
# @author OnApp Ltd.
|
2
6
|
class DSL
|
7
|
+
attr_reader :actions_and_rules
|
8
|
+
|
9
|
+
# @attr_reader [Array] actions_and_rules the resulting list of applied rules
|
3
10
|
def initialize(block)
|
4
|
-
|
5
|
-
end
|
11
|
+
@actions_and_rules = []
|
6
12
|
|
7
|
-
|
8
|
-
@actions_and_rules ||= []
|
13
|
+
instance_exec(&block)
|
9
14
|
end
|
10
15
|
|
16
|
+
# Executes the code inside a block after the record is *created*
|
11
17
|
def on_create(&block)
|
12
18
|
store(:create, Rules::CreateRule.new(block))
|
13
19
|
end
|
14
20
|
|
21
|
+
# Executes the code inside a block after the record is *destroyed*
|
15
22
|
def on_destroy(&block)
|
16
23
|
store(:destroy, Rules::DestroyRule.new(block))
|
17
24
|
end
|
18
25
|
|
26
|
+
# @param attributes [Symbols] - list of attribute names (e.g. :user_id, :user_group_id ...)
|
27
|
+
# @param values [Array(2)] - array of two values (before and after)
|
28
|
+
# Launches code inside a block if an object changes any of attributes according
|
29
|
+
# to the pattern which is described in the brackets (value before -> value after)
|
30
|
+
#
|
31
|
+
# This uses `===` method to compare values.
|
32
|
+
# @example Add hook on update any of attributes according to the pattern
|
33
|
+
# on_update :address, :phone_number, [CustomActiveRecordObserver::NotNill,
|
34
|
+
# CustomActiveRecordObserver::NotNill] do |user|
|
35
|
+
# # notify system that user contact info was changed
|
36
|
+
# end
|
37
|
+
#
|
38
|
+
# Will be launched only if user_group_id was changed from `nil` to anything but nil.
|
39
|
+
# in the array [] there are two values that are compared with the real changes
|
40
|
+
# to detect if they maches.
|
41
|
+
# @example Track nil -> not nill changes of user_group_id attribute
|
42
|
+
# on_update :user_group_id, [nil, CustomActiveRecordObserver::NotNill] do |user|
|
43
|
+
# # here we know that some user_group was assigned to user
|
44
|
+
# end
|
45
|
+
# @example Other examples of usage:
|
46
|
+
# on_update :user_group_id, [1, 2] { |user| ... }
|
47
|
+
# on_update :user_group_id, [1, Integer] { |user| ... }
|
19
48
|
def on_update(*attributes, &block)
|
20
49
|
pattern = attributes.pop if attributes.last.is_a?(Array)
|
21
50
|
|
@@ -24,14 +53,32 @@ module CustomActiveRecordObserver
|
|
24
53
|
end
|
25
54
|
end
|
26
55
|
|
56
|
+
# Executes the code inside a block when the specific attributes are *updated*
|
57
|
+
# from <tt>nil</tt> to some <tt>not nil</tt> value
|
58
|
+
# @example
|
59
|
+
# on_add :user_group_id do |user|
|
60
|
+
# # here we know that user_group_id was nil, but now it is not
|
61
|
+
# end
|
27
62
|
def on_add(*attributes, &block)
|
28
63
|
on_update(*attributes.push([nil, NotNil]), &block)
|
29
64
|
end
|
30
65
|
|
66
|
+
# Executes the code inside a block when the specific attributes are *updated*
|
67
|
+
# from some <tt>not nil</tt> value to <tt>nil</tt>
|
68
|
+
# @example
|
69
|
+
# on_remove :user_group_id do |user|
|
70
|
+
# # here we know that user_group_id is equal to nil now
|
71
|
+
# end
|
31
72
|
def on_remove(*attributes, &block)
|
32
73
|
on_update(*attributes.push([NotNil, nil]), &block)
|
33
74
|
end
|
34
75
|
|
76
|
+
# Executes the code inside a block when the specific attributes are *updated*
|
77
|
+
# from some <tt>not nil</tt> to another <tt>not nil</tt>
|
78
|
+
# @example
|
79
|
+
# on_change :user_group_id do |user|
|
80
|
+
# # user was assigned to another user group
|
81
|
+
# end
|
35
82
|
def on_change(*attributes, &block)
|
36
83
|
on_update(*attributes.push([NotNil, NotNil]), &block)
|
37
84
|
end
|
@@ -3,9 +3,15 @@ module CustomActiveRecordObserver
|
|
3
3
|
extend ActiveSupport::Concern
|
4
4
|
|
5
5
|
included do
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
if defined?(CollectiveIdea::Acts::NestedSet) && self < CollectiveIdea::Acts::NestedSet::Model
|
7
|
+
prepend CustomActiveRecordObserver::ChangesTracker[:set_depth!]
|
8
|
+
end
|
9
|
+
|
10
|
+
if try(:paranoid?)
|
11
|
+
include Paranoid
|
12
|
+
else
|
13
|
+
include Base
|
14
|
+
end
|
9
15
|
end
|
10
16
|
end
|
11
17
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CustomActiveRecordObserver
|
2
|
+
module Observable
|
3
|
+
# The base module which is included to all classes that are observed.
|
4
|
+
# It adds AR after commit callbacks to class instances and handles
|
5
|
+
# the results with <tt>CustomActiveRecordObserver::Handler</tt>
|
6
|
+
module Base
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
included do
|
10
|
+
after_commit -> { CustomActiveRecordObserver::Handler.(self, :create, previous_changes) }, on: :create
|
11
|
+
after_commit -> { CustomActiveRecordObserver::Handler.(self, :update, previous_changes) }, on: :update
|
12
|
+
after_commit -> { CustomActiveRecordObserver::Handler.(self, :destroy, previous_changes) }, on: :destroy
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module CustomActiveRecordObserver
|
2
|
+
module Observable
|
3
|
+
module Paranoid
|
4
|
+
extend ActiveSupport::Concern
|
5
|
+
|
6
|
+
included do
|
7
|
+
after_commit -> { CustomActiveRecordObserver::Handler.(self, :create, previous_changes) },
|
8
|
+
on: :create
|
9
|
+
after_commit -> { CustomActiveRecordObserver::Handler.(self, :update, previous_changes) },
|
10
|
+
on: :update
|
11
|
+
after_destroy -> { CustomActiveRecordObserver::Handler.(self, :destroy, previous_changes) },
|
12
|
+
if: -> { deleted_at }
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: custom_active_record_observer
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.5.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OnApp Ltd.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-08-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|
@@ -16,40 +16,28 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version: '
|
20
|
-
- - "<"
|
21
|
-
- !ruby/object:Gem::Version
|
22
|
-
version: '6'
|
19
|
+
version: '5.2'
|
23
20
|
type: :runtime
|
24
21
|
prerelease: false
|
25
22
|
version_requirements: !ruby/object:Gem::Requirement
|
26
23
|
requirements:
|
27
24
|
- - ">="
|
28
25
|
- !ruby/object:Gem::Version
|
29
|
-
version: '
|
30
|
-
- - "<"
|
31
|
-
- !ruby/object:Gem::Version
|
32
|
-
version: '6'
|
26
|
+
version: '5.2'
|
33
27
|
- !ruby/object:Gem::Dependency
|
34
28
|
name: railties
|
35
29
|
requirement: !ruby/object:Gem::Requirement
|
36
30
|
requirements:
|
37
31
|
- - ">="
|
38
32
|
- !ruby/object:Gem::Version
|
39
|
-
version: '
|
40
|
-
- - "<"
|
41
|
-
- !ruby/object:Gem::Version
|
42
|
-
version: '6'
|
33
|
+
version: '5.2'
|
43
34
|
type: :runtime
|
44
35
|
prerelease: false
|
45
36
|
version_requirements: !ruby/object:Gem::Requirement
|
46
37
|
requirements:
|
47
38
|
- - ">="
|
48
39
|
- !ruby/object:Gem::Version
|
49
|
-
version: '
|
50
|
-
- - "<"
|
51
|
-
- !ruby/object:Gem::Version
|
52
|
-
version: '6'
|
40
|
+
version: '5.2'
|
53
41
|
- !ruby/object:Gem::Dependency
|
54
42
|
name: rspec
|
55
43
|
requirement: !ruby/object:Gem::Requirement
|
@@ -78,6 +66,34 @@ dependencies:
|
|
78
66
|
- - ">="
|
79
67
|
- !ruby/object:Gem::Version
|
80
68
|
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: appraisal
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: pry
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
81
97
|
description: |2
|
82
98
|
This gem delivers a simple DSL based on the after_commit callback
|
83
99
|
which can be used as an alternative to hooks from inside the model
|
@@ -98,6 +114,8 @@ files:
|
|
98
114
|
- lib/custom_active_record_observer/models_extender.rb
|
99
115
|
- lib/custom_active_record_observer/not_nil.rb
|
100
116
|
- lib/custom_active_record_observer/observable.rb
|
117
|
+
- lib/custom_active_record_observer/observable/base.rb
|
118
|
+
- lib/custom_active_record_observer/observable/paranoid.rb
|
101
119
|
- lib/custom_active_record_observer/rules/all.rb
|
102
120
|
- lib/custom_active_record_observer/rules/base_rule.rb
|
103
121
|
- lib/custom_active_record_observer/rules/create_rule.rb
|
@@ -117,7 +135,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
117
135
|
requirements:
|
118
136
|
- - ">="
|
119
137
|
- !ruby/object:Gem::Version
|
120
|
-
version: 2.
|
138
|
+
version: 2.5.6
|
121
139
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
122
140
|
requirements:
|
123
141
|
- - ">="
|
@@ -125,7 +143,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
125
143
|
version: '0'
|
126
144
|
requirements: []
|
127
145
|
rubyforge_project:
|
128
|
-
rubygems_version: 2.
|
146
|
+
rubygems_version: 2.7.6.2
|
129
147
|
signing_key:
|
130
148
|
specification_version: 4
|
131
149
|
summary: A small handy library to track create/update/destroy actions on active_record
|