custom_active_record_observer 0.3.0 → 0.3.1
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 +4 -4
- data/README.md +86 -12
- data/lib/custom_active_record_observer.rb +36 -0
- 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/base.rb +3 -0
- data/lib/custom_active_record_observer/schema.rb +4 -0
- data/lib/custom_active_record_observer/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4af7438aff8a12f47958c45d93a0fa4da7efbcba
|
4
|
+
data.tar.gz: 00116ca29ecc84e69dac009c5313a265e0697578
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d0718789103b5aaac520e90497227f4484877317f3351b37dba4104a2b45839847d502b818682829fca542e19dfcc5b1e94f9723cb8dd454e2f918f4f0d4679e
|
7
|
+
data.tar.gz: 5ad0514aa41b98a010e30f8c714f30cd0f01c12b5a520de5c76f3c6f390b43d440eb132d96685b51e81ae0bf31f9e963668a7e7bb6e9f09e9849447f9ef5d393
|
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)|
|
@@ -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
|
@@ -1,5 +1,8 @@
|
|
1
1
|
module CustomActiveRecordObserver
|
2
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>
|
3
6
|
module Base
|
4
7
|
extend ActiveSupport::Concern
|
5
8
|
|
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.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- OnApp Ltd.
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-
|
11
|
+
date: 2018-03-05 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activerecord
|