custom_active_record_observer 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- 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 Version](https://badge.fury.io/rb/custom_active_record_observer.svg)][gem]
|
7
|
+
[![Build Status](https://travis-ci.org/OnApp/custom_active_record_observer.svg?branch=master)][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
|