active_interaction-extras 0.2.2 → 1.0.3
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/.github/workflows/ci.yml +35 -0
- data/CHANGELOG.md +33 -0
- data/README.md +156 -14
- data/Rakefile +9 -1
- data/active_interaction-extras.gemspec +11 -5
- data/lib/active_interaction/extras.rb +24 -2
- data/lib/active_interaction/extras/active_job.rb +25 -3
- data/lib/active_interaction/extras/all.rb +4 -1
- data/lib/active_interaction/extras/filter_alias.rb +18 -0
- data/lib/active_interaction/extras/filter_extensions.rb +2 -0
- data/lib/active_interaction/extras/filter_extensions/hash_auto_strip.rb +25 -0
- data/lib/active_interaction/extras/filter_extensions/object_classes.rb +47 -0
- data/lib/active_interaction/extras/filter_extensions/timezone_support.rb +16 -0
- data/lib/active_interaction/extras/filters/anything_filter.rb +9 -0
- data/lib/active_interaction/extras/filters/uuid_filter.rb +15 -0
- data/lib/active_interaction/extras/jobs/core.rb +32 -0
- data/lib/active_interaction/extras/locale/en.yml +5 -0
- data/lib/active_interaction/extras/model_fields.rb +5 -1
- data/lib/active_interaction/extras/rspec.rb +1 -1
- data/lib/active_interaction/extras/sidekiq.rb +61 -3
- data/lib/active_interaction/extras/strong_params.rb +1 -1
- data/lib/active_interaction/extras/transaction.rb +14 -19
- data/lib/active_interaction/extras/version.rb +1 -1
- metadata +59 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: c3637e9bc034e39019c7a5273730c9c66e39257fcb7006f8cb153318c2345acf
|
4
|
+
data.tar.gz: 51d7d883e0cfab7d0eae0f15b764f2b9e3f0868372cc4329fe47785014669e98
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 798047a1473aec22f030540ee4af4f7d074c7372cde93b9ceedcec996cc368d88c2e48743f7a0868da2029549f1e155c70037be36e252e7b5877caf64268bbbb
|
7
|
+
data.tar.gz: 38890669f04e15239b5ace15841dbb39e2a048eb9881ce127d80ad5b33126396417b5be918d8bef7a8b5a67bb1973fde82e2378baa0ce8b8dc00973d44546558
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# This workflow uses actions that are not certified by GitHub.
|
2
|
+
# They are provided by a third-party and are governed by
|
3
|
+
# separate terms of service, privacy policy, and support
|
4
|
+
# documentation.
|
5
|
+
# This workflow will download a prebuilt Ruby version, install dependencies and run tests with Rake
|
6
|
+
# For more information see: https://github.com/marketplace/actions/setup-ruby-jruby-and-truffleruby
|
7
|
+
|
8
|
+
name: Tests
|
9
|
+
|
10
|
+
on:
|
11
|
+
push:
|
12
|
+
branches: [ master ]
|
13
|
+
pull_request:
|
14
|
+
branches: [ master ]
|
15
|
+
|
16
|
+
jobs:
|
17
|
+
test:
|
18
|
+
|
19
|
+
runs-on: ubuntu-latest
|
20
|
+
strategy:
|
21
|
+
matrix:
|
22
|
+
ruby-version: ['2.6', '2.7', '3.0']
|
23
|
+
|
24
|
+
steps:
|
25
|
+
- uses: actions/checkout@v2
|
26
|
+
- name: Set up Ruby
|
27
|
+
# To automatically get bug fixes and new Ruby versions for ruby/setup-ruby,
|
28
|
+
# change this to (see https://github.com/ruby/setup-ruby#versioning):
|
29
|
+
# uses: ruby/setup-ruby@v1
|
30
|
+
uses: ruby/setup-ruby@473e4d8fe5dd94ee328fdfca9f8c9c7afc9dae5e
|
31
|
+
with:
|
32
|
+
ruby-version: ${{ matrix.ruby-version }}
|
33
|
+
bundler-cache: true # runs 'bundle install' and caches installed gems automatically
|
34
|
+
- name: Run tests
|
35
|
+
run: bundle exec rake
|
data/CHANGELOG.md
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# Change Log
|
2
|
+
All notable changes to this project will be documented in this file.
|
3
|
+
This project adheres to [Semantic Versioning](http://semver.org/).
|
4
|
+
|
5
|
+
## [Unreleased]
|
6
|
+
|
7
|
+
## [1.0.3] - 2021-07-11
|
8
|
+
|
9
|
+
- Loosen the gem requirements
|
10
|
+
|
11
|
+
## [1.0.2] - 2021-07-07
|
12
|
+
|
13
|
+
- Requires active_interaction v4.0.2 or higher
|
14
|
+
- Fixed `run_in_transaction!` to rollback when interaction finished with errors
|
15
|
+
|
16
|
+
## [1.0.1] - 2021-05-13
|
17
|
+
|
18
|
+
- Fix `run_in_transaction` in ruby 3 [#8](https://github.com/antulik/active_interaction-extras/pull/8)
|
19
|
+
|
20
|
+
## [1.0.0] - 2021-05-12
|
21
|
+
|
22
|
+
- Requires active_interaction v4
|
23
|
+
- New filters: `anything` and `uuid`
|
24
|
+
- New filter extensions
|
25
|
+
- object: support for multiple classes
|
26
|
+
- hash: disable auto strip when no keys are listed
|
27
|
+
- New extension:
|
28
|
+
- filter alias
|
29
|
+
- Changed `transaction` extension
|
30
|
+
- It requires new transaction by default
|
31
|
+
- Include order is important now
|
32
|
+
- Removed `active_interaction-active_job` gem dependency
|
33
|
+
- Added changelog
|
data/README.md
CHANGED
@@ -1,26 +1,115 @@
|
|
1
1
|
# ActiveInteraction::Extras
|
2
2
|
|
3
|
+
[](https://badge.fury.io/rb/active_interaction-extras) 
|
4
|
+
|
3
5
|
This gem contains the collection of useful extensions to [active_interaction](https://github.com/AaronLasseigne/active_interaction) gem.
|
4
6
|
|
7
|
+
- [Installation](#installation)
|
8
|
+
- [Basic Usage](#basic-usage)
|
9
|
+
- [Filters](#filters)
|
10
|
+
- [Anything](#anything)
|
11
|
+
- [UUID](#uuid)
|
12
|
+
- [Filter Extensions](#filter-extensions)
|
13
|
+
- [Hash: auto strip](#hash-auto-strip)
|
14
|
+
- [Object: multiple classes](#object-multiple-classes)
|
15
|
+
- [Extensions](#extensions)
|
16
|
+
- [Filter alias](#filter-alias)
|
17
|
+
- [Halt](#halt)
|
18
|
+
- [ModelFields](#modelfields)
|
19
|
+
- [RunCallback](#runcallback)
|
20
|
+
- [StrongParams](#strongparams)
|
21
|
+
- [Transaction](#transaction)
|
22
|
+
- [Jobs](#jobs)
|
23
|
+
- [ActiveJob](#activejob)
|
24
|
+
- [Sidekiq](#sidekiq)
|
25
|
+
- [RSpec](#rspec)
|
26
|
+
|
5
27
|
## Installation
|
6
28
|
|
7
29
|
```ruby
|
8
30
|
gem 'active_interaction-extras'
|
9
31
|
```
|
10
32
|
|
11
|
-
## Usage
|
12
|
-
|
13
|
-
### All
|
33
|
+
## Basic Usage
|
14
34
|
|
15
35
|
```ruby
|
36
|
+
# app/services/application_interaction.rb
|
16
37
|
class ApplicationInteraction < ActiveInteraction::Base
|
17
38
|
include ActiveInteraction::Extras::All
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
39
|
+
end
|
40
|
+
```
|
41
|
+
|
42
|
+
## Filters
|
43
|
+
|
44
|
+
These new filters are added automatically when gem is loaded.
|
45
|
+
|
46
|
+
### Anything
|
47
|
+
|
48
|
+
Anything filter accepts as you guest it - anything.
|
49
|
+
|
50
|
+
```ruby
|
51
|
+
class Service < ActiveInteraction::Base
|
52
|
+
anything :model
|
53
|
+
end
|
54
|
+
```
|
55
|
+
|
56
|
+
### UUID
|
57
|
+
|
58
|
+
```ruby
|
59
|
+
class Service < ActiveInteraction::Base
|
60
|
+
uuid :id
|
61
|
+
end
|
62
|
+
```
|
63
|
+
|
64
|
+
## Filter Extensions
|
65
|
+
|
66
|
+
You can load all filter extensions with:
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
# config/initializers/active_interaction.rb
|
70
|
+
require 'active_interaction/extras/filter_extensions'
|
71
|
+
```
|
72
|
+
|
73
|
+
### Hash: auto strip
|
74
|
+
|
75
|
+
This small extensions allows to accept full hashes without explicit `strip` option.
|
76
|
+
|
77
|
+
```ruby
|
78
|
+
class Service < ActiveInteraction::Base
|
79
|
+
hash :options_a, strip: false # (Before) Accept all keys
|
80
|
+
|
81
|
+
hash :options_b # (After) Accept all keys
|
82
|
+
|
83
|
+
hash :options_c do # (Before and After) Accept only specified keys
|
84
|
+
string :name
|
85
|
+
end
|
86
|
+
end
|
87
|
+
```
|
88
|
+
|
89
|
+
### Object: multiple classes
|
90
|
+
|
91
|
+
This extension allows using `object` filter with multiple classes.
|
92
|
+
|
93
|
+
```ruby
|
94
|
+
class Service < ActiveInteraction::Base
|
95
|
+
object :user, class: [User, AdminUser]
|
96
|
+
end
|
97
|
+
```
|
98
|
+
|
99
|
+
|
100
|
+
## Extensions
|
101
|
+
|
102
|
+
### Filter Alias
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class Service < ActiveInteraction::Base
|
106
|
+
include ActiveInteraction::Extras::FilterAlias
|
107
|
+
|
108
|
+
hash :params, as: :user_attributes
|
109
|
+
|
110
|
+
def execute
|
111
|
+
user_attributes == params # => true
|
112
|
+
end
|
24
113
|
end
|
25
114
|
```
|
26
115
|
|
@@ -50,7 +139,7 @@ end
|
|
50
139
|
class UserForm < ActiveInteraction::Base
|
51
140
|
include ActiveInteraction::Extras::ModelFields
|
52
141
|
|
53
|
-
|
142
|
+
anything :user
|
54
143
|
|
55
144
|
model_fields(:user) do
|
56
145
|
string :first_name
|
@@ -96,7 +185,6 @@ end
|
|
96
185
|
|
97
186
|
### StrongParams
|
98
187
|
|
99
|
-
|
100
188
|
```ruby
|
101
189
|
class UpdateUserForm < ActiveInteraction::Base
|
102
190
|
include ActiveInteraction::Extras::StrongParams
|
@@ -149,6 +237,10 @@ UpdateUserForm.run
|
|
149
237
|
Comment.count # => 0
|
150
238
|
```
|
151
239
|
|
240
|
+
## Jobs
|
241
|
+
|
242
|
+
You no longer need to create a separate Job class for the each interaction. This Job extension automatically converts interactions to background jobs. By convention each interaction will have a nested `Job` class which will be inherited from the parent interaction `Job` class (e.g. `ApplicationInteraction::Job`).
|
243
|
+
|
152
244
|
### ActiveJob
|
153
245
|
|
154
246
|
```ruby
|
@@ -169,10 +261,15 @@ class DoubleService < ApplicationInteraction
|
|
169
261
|
end
|
170
262
|
|
171
263
|
DoubleService.delay.run(x: 2) # queues to run in background
|
264
|
+
DoubleService.delay(queue: 'low_priority', wait: 1.minute).run(x: 2)
|
172
265
|
```
|
173
266
|
|
267
|
+
In ActiveJob mode `delay` method accepts anything ActiveJob `set` [method](https://edgeapi.rubyonrails.org/classes/ActiveJob/Core/ClassMethods.html#method-i-set) does. (`wait`, `wait_until`, `queue`, `priority`)
|
268
|
+
|
174
269
|
### Sidekiq
|
175
270
|
|
271
|
+
You can use sidekiq directly if you need more control. Sidekiq integration comes with default GlobalID support.
|
272
|
+
|
176
273
|
```ruby
|
177
274
|
class ApplicationInteraction < ActiveInteraction::Base
|
178
275
|
include ActiveInteraction::Extras::Sidekiq
|
@@ -185,7 +282,7 @@ end
|
|
185
282
|
|
186
283
|
class DoubleService < ApplicationInteraction
|
187
284
|
job do
|
188
|
-
sidekiq_options retry: 1
|
285
|
+
sidekiq_options retry: 1 # configure sidekiq options
|
189
286
|
end
|
190
287
|
|
191
288
|
integer :x
|
@@ -196,9 +293,53 @@ class DoubleService < ApplicationInteraction
|
|
196
293
|
end
|
197
294
|
|
198
295
|
DoubleService.delay.run(x: 2) # queues to run in background
|
296
|
+
DoubleService.delay(queue: 'low_priority', wait: 1.minute).run(x: 2)
|
297
|
+
```
|
298
|
+
|
299
|
+
In Sidekiq mode `delay` method accepts anything sidekiq `set` [method](https://github.com/mperham/sidekiq/wiki/Advanced-Options#workers) does (`queue`, `retry`, `backtrace`, etc). Plus two additional `wait` and `wait_until`.
|
300
|
+
|
301
|
+
```ruby
|
302
|
+
# Advance usage: retry based on given params
|
303
|
+
class DoubleService < ApplicationInteraction
|
304
|
+
job do
|
305
|
+
sidekiq_options(retry: ->(job) {
|
306
|
+
params = deserialize_active_job_args(job)
|
307
|
+
params[:x]
|
308
|
+
})
|
309
|
+
end
|
310
|
+
|
311
|
+
integer :x
|
312
|
+
|
313
|
+
def execute
|
314
|
+
x + x
|
315
|
+
end
|
316
|
+
end
|
317
|
+
```
|
318
|
+
|
319
|
+
```ruby
|
320
|
+
# Advance usage: Rescue the job but not service
|
321
|
+
class DoubleService < ApplicationInteraction
|
322
|
+
job do
|
323
|
+
def perform(*args)
|
324
|
+
super
|
325
|
+
rescue StandardError => e
|
326
|
+
params = deserialize_active_job_args(args)
|
327
|
+
params[:x]
|
328
|
+
end
|
329
|
+
end
|
330
|
+
|
331
|
+
integer :x
|
332
|
+
|
333
|
+
def execute
|
334
|
+
raise
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
DoubleService.run # => RuntimeError
|
339
|
+
DoubleService.delay.perform_now(x: 2) # => returns 2
|
199
340
|
```
|
200
341
|
|
201
|
-
|
342
|
+
## Rspec
|
202
343
|
|
203
344
|
```ruby
|
204
345
|
class SomeService < ActiveInteraction::Base
|
@@ -249,7 +390,8 @@ The gem is available as open source under the terms of the [MIT License](https:/
|
|
249
390
|
|
250
391
|
## Credits
|
251
392
|
|
252
|
-
ActiveInteraction::Extras is brought to you by [Anton Katunin](https://github.com/antulik) and was originally built at [CarNextDoor](https://www.carnextdoor.com.au/).
|
393
|
+
* ActiveInteraction::Extras is brought to you by [Anton Katunin](https://github.com/antulik) and was originally built at [CarNextDoor](https://www.carnextdoor.com.au/).
|
394
|
+
* Further improvements to this gem brought to you by [Anton Katunin](https://github.com/antulik) once again and the [Split Payments team](https://github.com/splitpayments/split).
|
253
395
|
|
254
396
|
## Code of Conduct
|
255
397
|
|
data/Rakefile
CHANGED
@@ -13,6 +13,9 @@ Gem::Specification.new do |spec|
|
|
13
13
|
spec.description = %q{Extensions for active_interaction gem}
|
14
14
|
spec.homepage = "https://github.com/antulik/active_interaction-extras"
|
15
15
|
spec.license = "MIT"
|
16
|
+
spec.metadata = {
|
17
|
+
"changelog_uri" => "https://github.com/antulik/active_interaction-extras/blob/master/CHANGELOG.md",
|
18
|
+
}
|
16
19
|
|
17
20
|
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
21
|
f.match(%r{^(test|spec|features)/})
|
@@ -21,11 +24,14 @@ Gem::Specification.new do |spec|
|
|
21
24
|
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
22
25
|
spec.require_paths = ["lib"]
|
23
26
|
|
24
|
-
spec.add_dependency "active_interaction", ">=
|
25
|
-
spec.add_dependency "
|
26
|
-
spec.
|
27
|
-
|
27
|
+
spec.add_dependency "active_interaction", ">= 4.0.2"
|
28
|
+
spec.add_dependency "activemodel", ">= 6.0"
|
29
|
+
spec.add_dependency "activesupport", ">= 6.0"
|
30
|
+
|
31
|
+
spec.add_development_dependency "bundler", "~> 2.2"
|
32
|
+
spec.add_development_dependency "rake", ">= 12.3.3"
|
28
33
|
spec.add_development_dependency "rspec", "~> 3.7"
|
29
|
-
spec.add_development_dependency "rails", ">= 4.0"
|
30
34
|
spec.add_development_dependency "pry"
|
35
|
+
spec.add_development_dependency "sqlite3"
|
36
|
+
spec.add_development_dependency "activerecord"
|
31
37
|
end
|
@@ -5,18 +5,40 @@ require 'active_interaction'
|
|
5
5
|
|
6
6
|
module ActiveInteraction
|
7
7
|
module Extras
|
8
|
+
module Filters
|
9
|
+
end
|
10
|
+
|
11
|
+
module FilterExtensions
|
12
|
+
end
|
13
|
+
|
14
|
+
module Jobs
|
15
|
+
autoload(:Core, "active_interaction/extras/jobs/core")
|
16
|
+
end
|
8
17
|
|
9
18
|
autoload(:All, "active_interaction/extras/all")
|
10
19
|
|
20
|
+
autoload(:FilterAlias, "active_interaction/extras/filter_alias")
|
11
21
|
autoload(:Halt, "active_interaction/extras/halt")
|
12
22
|
autoload(:ModelFields, "active_interaction/extras/model_fields")
|
13
23
|
autoload(:RunCallback, "active_interaction/extras/run_callback")
|
14
24
|
autoload(:StrongParams, "active_interaction/extras/strong_params")
|
15
25
|
autoload(:Transaction, "active_interaction/extras/transaction")
|
16
26
|
|
27
|
+
autoload(:TimezoneSupport, "active_interaction/extras/timezone_support")
|
28
|
+
autoload(:Rspec, "active_interaction/extras/rspec")
|
29
|
+
|
17
30
|
autoload(:ActiveJob, "active_interaction/extras/active_job")
|
18
31
|
autoload(:Sidekiq, "active_interaction/extras/sidekiq")
|
19
|
-
|
20
|
-
autoload(:Rspec, "active_interaction/extras/rspec")
|
21
32
|
end
|
22
33
|
end
|
34
|
+
|
35
|
+
require 'active_interaction/extras/filters/anything_filter'
|
36
|
+
require 'active_interaction/extras/filters/uuid_filter'
|
37
|
+
|
38
|
+
I18n.load_path.unshift(
|
39
|
+
*Dir.glob(
|
40
|
+
File.expand_path(
|
41
|
+
File.join(%w[extras locale *.yml]), File.dirname(__FILE__)
|
42
|
+
)
|
43
|
+
)
|
44
|
+
)
|
@@ -1,13 +1,35 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_job'
|
2
2
|
|
3
3
|
module ActiveInteraction::Extras::ActiveJob
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
include ActiveInteraction::
|
6
|
+
include ActiveInteraction::Extras::Jobs::Core
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
def configured_job_class
|
10
|
+
ConfiguredJob
|
11
|
+
end
|
12
|
+
end
|
7
13
|
|
8
14
|
module Perform
|
9
15
|
extend ActiveSupport::Concern
|
10
16
|
|
11
|
-
|
17
|
+
def perform(*args)
|
18
|
+
if self.class.respond_to?(:module_parent)
|
19
|
+
self.class.module_parent.run!(*args)
|
20
|
+
else
|
21
|
+
self.class.parent.run!(*args)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class ConfiguredJob < ::ActiveJob::ConfiguredJob
|
27
|
+
def run(*args)
|
28
|
+
perform_later(*args)
|
29
|
+
end
|
30
|
+
|
31
|
+
def run!(*args)
|
32
|
+
perform_later(*args)
|
33
|
+
end
|
12
34
|
end
|
13
35
|
end
|
@@ -1,9 +1,12 @@
|
|
1
1
|
module ActiveInteraction::Extras::All
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
+
# order dependant, include first so around callback includes other modules
|
5
|
+
include ActiveInteraction::Extras::Transaction
|
6
|
+
|
7
|
+
include ActiveInteraction::Extras::FilterAlias
|
4
8
|
include ActiveInteraction::Extras::Halt
|
5
9
|
include ActiveInteraction::Extras::ModelFields
|
6
10
|
include ActiveInteraction::Extras::RunCallback
|
7
11
|
include ActiveInteraction::Extras::StrongParams
|
8
|
-
include ActiveInteraction::Extras::Transaction
|
9
12
|
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Add :as option, which is a read alias to filter
|
4
|
+
# hash :params, as: :account_attributes
|
5
|
+
#
|
6
|
+
module ActiveInteraction::Extras::FilterAlias
|
7
|
+
extend ActiveSupport::Concern
|
8
|
+
|
9
|
+
class_methods do
|
10
|
+
def initialize_filter(filter)
|
11
|
+
super.tap do
|
12
|
+
if filter.options[:as]
|
13
|
+
alias_method filter.options[:as], filter.name
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# If hash specified without structure automatically accept full hash
|
4
|
+
#
|
5
|
+
# @example Accept all keys
|
6
|
+
# hash :options
|
7
|
+
#
|
8
|
+
# @example Accept only specified keys
|
9
|
+
# hash :options do
|
10
|
+
# string :name
|
11
|
+
# end
|
12
|
+
#
|
13
|
+
# @example Accept all keys
|
14
|
+
# hash :options, strip: false do
|
15
|
+
# string :name
|
16
|
+
# end
|
17
|
+
#
|
18
|
+
module ActiveInteraction::Extras::FilterExtensions::HashAutoStrip
|
19
|
+
def initialize(*)
|
20
|
+
super
|
21
|
+
options[:strip] = false if !block_given? && !options.key?(:strip)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
ActiveInteraction::HashFilter.prepend(ActiveInteraction::Extras::FilterExtensions::HashAutoStrip)
|
@@ -0,0 +1,47 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Add support for polymorphic objects
|
4
|
+
# object :account, class: [Account, AnyoneAccount]
|
5
|
+
#
|
6
|
+
module ActiveInteraction::Extras::FilterExtensions::ObjectClasses
|
7
|
+
def class_list
|
8
|
+
class_names.map do |klass_name|
|
9
|
+
case klass_name
|
10
|
+
when Class
|
11
|
+
klass_name
|
12
|
+
else
|
13
|
+
begin
|
14
|
+
Object.const_get(klass_name.to_s.camelize)
|
15
|
+
rescue NameError
|
16
|
+
raise ActiveInteraction::InvalidNameError, "class #{klass_name.inspect} does not exist"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def klass
|
23
|
+
if polymorphic?
|
24
|
+
class_list.first
|
25
|
+
else
|
26
|
+
super
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def matches?(value)
|
31
|
+
if polymorphic?
|
32
|
+
class_list.any? { |klass| value.class <= klass }
|
33
|
+
else
|
34
|
+
super
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def class_names
|
39
|
+
options.fetch(:class, name)
|
40
|
+
end
|
41
|
+
|
42
|
+
def polymorphic?
|
43
|
+
class_names.is_a? Array
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
ActiveInteraction::ObjectFilter.prepend(ActiveInteraction::Extras::FilterExtensions::ObjectClasses)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
# Implementation inspired by
|
4
|
+
# https://github.com/AaronLasseigne/active_interaction/blob/c9d5608c3b8aab23d463f99c832b2ac5139911de/lib/active_interaction/filters/abstract_date_time_filter.rb#L42
|
5
|
+
module ActiveInteraction::Extras::FilterExtensions::TimezoneSupport
|
6
|
+
def convert_string(value)
|
7
|
+
if time_with_zone?
|
8
|
+
Time.zone.parse(value) ||
|
9
|
+
raise(ArgumentError, "no time information in #{value.inspect}")
|
10
|
+
else
|
11
|
+
super
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
ActiveInteraction::TimeFilter.include(ActiveInteraction::Extras::FilterExtensions::TimezoneSupport)
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class ActiveInteraction::Extras::Filters::UUIDFilter < ActiveInteraction::StringFilter
|
4
|
+
register :uuid
|
5
|
+
|
6
|
+
REGEX = /^[0-9A-F]{8}-[0-9A-F]{4}-[4][0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i.freeze
|
7
|
+
|
8
|
+
def matches?(value)
|
9
|
+
super && REGEX.match?(value)
|
10
|
+
end
|
11
|
+
|
12
|
+
def convert(value)
|
13
|
+
super&.presence
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module ActiveInteraction::Extras::Jobs::Core
|
2
|
+
extend ActiveSupport::Concern
|
3
|
+
|
4
|
+
class_methods do
|
5
|
+
def define_job_class(klass)
|
6
|
+
unless const_defined?(:Job, false)
|
7
|
+
const_set(:Job, Class.new(klass))
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def job(&block)
|
12
|
+
job_class.class_exec(&block)
|
13
|
+
end
|
14
|
+
|
15
|
+
def job_class
|
16
|
+
const_get(:Job, false)
|
17
|
+
end
|
18
|
+
|
19
|
+
def inherited(subclass)
|
20
|
+
super
|
21
|
+
subclass.define_job_class(job_class)
|
22
|
+
end
|
23
|
+
|
24
|
+
def delay(options = {})
|
25
|
+
configured_job_class.new(job_class, options)
|
26
|
+
end
|
27
|
+
|
28
|
+
def configured_job_class
|
29
|
+
raise NotImplementedError
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -46,6 +46,10 @@ module ActiveInteraction::Extras::ModelFields
|
|
46
46
|
alias file custom_filter_attribute
|
47
47
|
alias boolean custom_filter_attribute
|
48
48
|
alias array custom_filter_attribute
|
49
|
+
alias record custom_filter_attribute
|
50
|
+
|
51
|
+
alias anything custom_filter_attribute
|
52
|
+
alias uuid custom_filter_attribute
|
49
53
|
end
|
50
54
|
|
51
55
|
# checks if value was given to the service and the value is different from
|
@@ -64,7 +68,7 @@ module ActiveInteraction::Extras::ModelFields
|
|
64
68
|
end
|
65
69
|
|
66
70
|
# overwritten to pre-populate model fields
|
67
|
-
def
|
71
|
+
def populate_filters_and_inputs(_inputs)
|
68
72
|
super.tap do
|
69
73
|
self.class.filters.each do |name, filter|
|
70
74
|
next if given?(name)
|
@@ -1,13 +1,71 @@
|
|
1
|
-
require '
|
1
|
+
require 'active_job'
|
2
2
|
|
3
3
|
module ActiveInteraction::Extras::Sidekiq
|
4
4
|
extend ActiveSupport::Concern
|
5
5
|
|
6
|
-
include ActiveInteraction::
|
6
|
+
include ActiveInteraction::Extras::Jobs::Core
|
7
|
+
|
8
|
+
class_methods do
|
9
|
+
def configured_job_class
|
10
|
+
ConfiguredJob
|
11
|
+
end
|
12
|
+
end
|
7
13
|
|
8
14
|
module Perform
|
9
15
|
extend ActiveSupport::Concern
|
10
16
|
|
11
|
-
|
17
|
+
class_methods do
|
18
|
+
def deserialize_active_job_args(serialized_job)
|
19
|
+
ActiveJob::Arguments.deserialize(serialized_job['args']).first&.with_indifferent_access || {}
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform_later(*args)
|
23
|
+
ConfiguredJob.new(self).perform_later(*args)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
def perform(*args)
|
28
|
+
# support for sidekiq encrypted params
|
29
|
+
if args.length > 1 && args[0].nil?
|
30
|
+
args.shift
|
31
|
+
end
|
32
|
+
|
33
|
+
args = ActiveJob::Arguments.deserialize(args)
|
34
|
+
if self.class.respond_to?(:module_parent)
|
35
|
+
self.class.module_parent.run!(*args)
|
36
|
+
else
|
37
|
+
self.class.parent.run!(*args)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def deserialize_active_job_args(job_arguments)
|
42
|
+
ActiveJob::Arguments.deserialize(job_arguments).first&.with_indifferent_access || {}
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
class ConfiguredJob < ::ActiveJob::ConfiguredJob
|
47
|
+
def perform_now(*args)
|
48
|
+
@job_class.run!(*args)
|
49
|
+
end
|
50
|
+
|
51
|
+
def perform_later(*args)
|
52
|
+
args = ActiveJob::Arguments.serialize(args)
|
53
|
+
scope = @job_class.set(@options.except(:wait, :wait_until))
|
54
|
+
|
55
|
+
if @job_class.sidekiq_options['encrypt']
|
56
|
+
args.prepend(nil)
|
57
|
+
end
|
58
|
+
|
59
|
+
if @options[:wait]
|
60
|
+
scope.perform_in @options[:wait], *args
|
61
|
+
elsif @options[:wait_until]
|
62
|
+
scope.perform_at @options[:wait_until], *args
|
63
|
+
else
|
64
|
+
scope.perform_async *args
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
alias_method :run!, :perform_later
|
69
|
+
alias_method :run, :perform_later
|
12
70
|
end
|
13
71
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module ActiveInteraction::Extras::StrongParams
|
2
2
|
extend ActiveSupport::Concern
|
3
3
|
|
4
|
-
def
|
4
|
+
def initialize(inputs = {})
|
5
5
|
# TODO: whitelist :params and :form_params, so they could not be used as filters
|
6
6
|
return super if self.class.filters.key?(:params) || self.class.filters.key?(:form_params)
|
7
7
|
|
@@ -1,32 +1,27 @@
|
|
1
|
+
# Add transaction wrapper
|
2
|
+
# run_in_transaction!
|
3
|
+
# skip_run_in_transaction!
|
1
4
|
module ActiveInteraction::Extras::Transaction
|
2
5
|
extend ActiveSupport::Concern
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
# errors added by compose method are merged after execute,
|
11
|
-
# so we need to check return type ourselves
|
12
|
-
#
|
13
|
-
# see ActiveInteraction::Runnable#run
|
14
|
-
if result_or_errors.is_a?(ActiveInteraction::Errors) && result_or_errors.any?
|
15
|
-
raise ActiveRecord::Rollback
|
7
|
+
included do
|
8
|
+
class_attribute :run_in_transaction_options
|
9
|
+
set_callback :execute, :around, ->(_interaction, block) {
|
10
|
+
ActiveRecord::Base.transaction(**run_in_transaction_options) do
|
11
|
+
block.call
|
12
|
+
raise ActiveRecord::Rollback if _interaction.errors.any?
|
16
13
|
end
|
17
|
-
|
18
|
-
raise ActiveRecord::Rollback if errors.any?
|
19
|
-
end
|
20
|
-
result_or_errors
|
14
|
+
}, if: :run_in_transaction_options
|
21
15
|
end
|
22
16
|
|
23
17
|
class_methods do
|
24
|
-
|
25
|
-
|
18
|
+
# https://pragtob.wordpress.com/2017/12/12/surprises-with-nested-transactions-rollbacks-and-activerecord/
|
19
|
+
def run_in_transaction!(requires_new: true)
|
20
|
+
self.run_in_transaction_options = {requires_new: requires_new}
|
26
21
|
end
|
27
22
|
|
28
23
|
def skip_run_in_transaction!
|
29
|
-
|
24
|
+
self.run_in_transaction_options = nil
|
30
25
|
end
|
31
26
|
end
|
32
27
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: active_interaction-extras
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 1.0.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Anton Katunin
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2021-07-11 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: active_interaction
|
@@ -16,56 +16,70 @@ dependencies:
|
|
16
16
|
requirements:
|
17
17
|
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
|
-
version:
|
19
|
+
version: 4.0.2
|
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:
|
26
|
+
version: 4.0.2
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
|
-
name:
|
28
|
+
name: activemodel
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
31
|
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
|
-
version: '0'
|
33
|
+
version: '6.0'
|
34
34
|
type: :runtime
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
38
|
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
|
-
version: '0'
|
40
|
+
version: '6.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: activesupport
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - ">="
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '6.0'
|
48
|
+
type: :runtime
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '6.0'
|
41
55
|
- !ruby/object:Gem::Dependency
|
42
56
|
name: bundler
|
43
57
|
requirement: !ruby/object:Gem::Requirement
|
44
58
|
requirements:
|
45
59
|
- - "~>"
|
46
60
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
61
|
+
version: '2.2'
|
48
62
|
type: :development
|
49
63
|
prerelease: false
|
50
64
|
version_requirements: !ruby/object:Gem::Requirement
|
51
65
|
requirements:
|
52
66
|
- - "~>"
|
53
67
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
68
|
+
version: '2.2'
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rake
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|
58
72
|
requirements:
|
59
|
-
- - "
|
73
|
+
- - ">="
|
60
74
|
- !ruby/object:Gem::Version
|
61
|
-
version:
|
75
|
+
version: 12.3.3
|
62
76
|
type: :development
|
63
77
|
prerelease: false
|
64
78
|
version_requirements: !ruby/object:Gem::Requirement
|
65
79
|
requirements:
|
66
|
-
- - "
|
80
|
+
- - ">="
|
67
81
|
- !ruby/object:Gem::Version
|
68
|
-
version:
|
82
|
+
version: 12.3.3
|
69
83
|
- !ruby/object:Gem::Dependency
|
70
84
|
name: rspec
|
71
85
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,21 +95,35 @@ dependencies:
|
|
81
95
|
- !ruby/object:Gem::Version
|
82
96
|
version: '3.7'
|
83
97
|
- !ruby/object:Gem::Dependency
|
84
|
-
name:
|
98
|
+
name: pry
|
85
99
|
requirement: !ruby/object:Gem::Requirement
|
86
100
|
requirements:
|
87
101
|
- - ">="
|
88
102
|
- !ruby/object:Gem::Version
|
89
|
-
version: '
|
103
|
+
version: '0'
|
90
104
|
type: :development
|
91
105
|
prerelease: false
|
92
106
|
version_requirements: !ruby/object:Gem::Requirement
|
93
107
|
requirements:
|
94
108
|
- - ">="
|
95
109
|
- !ruby/object:Gem::Version
|
96
|
-
version: '
|
110
|
+
version: '0'
|
97
111
|
- !ruby/object:Gem::Dependency
|
98
|
-
name:
|
112
|
+
name: sqlite3
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: activerecord
|
99
127
|
requirement: !ruby/object:Gem::Requirement
|
100
128
|
requirements:
|
101
129
|
- - ">="
|
@@ -115,8 +143,10 @@ executables: []
|
|
115
143
|
extensions: []
|
116
144
|
extra_rdoc_files: []
|
117
145
|
files:
|
146
|
+
- ".github/workflows/ci.yml"
|
118
147
|
- ".gitignore"
|
119
148
|
- ".rspec"
|
149
|
+
- CHANGELOG.md
|
120
150
|
- CODE_OF_CONDUCT.md
|
121
151
|
- Gemfile
|
122
152
|
- LICENSE.txt
|
@@ -128,7 +158,16 @@ files:
|
|
128
158
|
- lib/active_interaction/extras.rb
|
129
159
|
- lib/active_interaction/extras/active_job.rb
|
130
160
|
- lib/active_interaction/extras/all.rb
|
161
|
+
- lib/active_interaction/extras/filter_alias.rb
|
162
|
+
- lib/active_interaction/extras/filter_extensions.rb
|
163
|
+
- lib/active_interaction/extras/filter_extensions/hash_auto_strip.rb
|
164
|
+
- lib/active_interaction/extras/filter_extensions/object_classes.rb
|
165
|
+
- lib/active_interaction/extras/filter_extensions/timezone_support.rb
|
166
|
+
- lib/active_interaction/extras/filters/anything_filter.rb
|
167
|
+
- lib/active_interaction/extras/filters/uuid_filter.rb
|
131
168
|
- lib/active_interaction/extras/halt.rb
|
169
|
+
- lib/active_interaction/extras/jobs/core.rb
|
170
|
+
- lib/active_interaction/extras/locale/en.yml
|
132
171
|
- lib/active_interaction/extras/model_fields.rb
|
133
172
|
- lib/active_interaction/extras/rspec.rb
|
134
173
|
- lib/active_interaction/extras/run_callback.rb
|
@@ -139,7 +178,8 @@ files:
|
|
139
178
|
homepage: https://github.com/antulik/active_interaction-extras
|
140
179
|
licenses:
|
141
180
|
- MIT
|
142
|
-
metadata:
|
181
|
+
metadata:
|
182
|
+
changelog_uri: https://github.com/antulik/active_interaction-extras/blob/master/CHANGELOG.md
|
143
183
|
post_install_message:
|
144
184
|
rdoc_options: []
|
145
185
|
require_paths:
|
@@ -155,7 +195,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
155
195
|
- !ruby/object:Gem::Version
|
156
196
|
version: '0'
|
157
197
|
requirements: []
|
158
|
-
rubygems_version: 3.
|
198
|
+
rubygems_version: 3.1.4
|
159
199
|
signing_key:
|
160
200
|
specification_version: 4
|
161
201
|
summary: Extensions for active_interaction gem
|