You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: README.md
+33-73
Original file line number
Diff line number
Diff line change
@@ -1,15 +1,6 @@
1
1
# Interactify
2
2
3
-
[Interactors](https://github.com/collectiveidea/interactor) are a great way to encapsulate business logic in a Rails application.
4
-
However, sometimes in complex interactor chains, the complex debugging happens at one level up from your easy to read and test interactors.
5
-
6
-
[interactor-contracts](https://github.com/michaelherold/interactor-contracts) does a fantastic job of making your interactor chains more reliable.
7
-
8
-
Interactify wraps the interactor and interactor-contracts gem and provides additional functionality making chaining and understanding interactor chains easier.
9
-
10
-
This is a bells and whistles gem and assumes you are working in a Rails project with Sidekiq.
11
-
However, I'm open to the idea of making it more focused and making these more pluggable.
12
-
3
+
Interactify enhances Rails applications by simplifying complex interactor chains. This gem builds on [interactors](https://github.com/collectiveidea/interactor) and [interactor-contracts](https://github.com/michaelherold/interactor-contracts) to improve readability and maintainability of business logic. It's optimized for Rails projects using Sidekiq, offering advanced features for chain management and debugging. Interactify is about making interactor usage in Rails more efficient and less error-prone, reducing the overhead of traditional interactor orchestration.
- Everything is an Organizer/Interactor and supports interactor-contracts.
40
+
- They only becomes considered an organizer once `organize` is called.
41
+
- They could technically be both (if you want?) but you have to remember to call `super` within `call` to trigger the organized interactors.
49
42
- Concise syntax for most common scenarios with `expects` and `promises`. Verifying the presence of the keys/values.
50
43
- Automatic delegation of expected and promised keys to the context.
51
44
@@ -66,7 +59,6 @@ class LoadOrder
66
59
required(:order).filled
67
60
end
68
61
69
-
70
62
defcall
71
63
context.order =Order.find(context.id)
72
64
end
@@ -92,8 +84,8 @@ end
92
84
93
85
### Lambdas
94
86
95
-
With vanilla interactors, it's not possible to use lambdas in organizers, and sometimes we only want a lambda.
96
-
So we added support.
87
+
With vanilla interactors, it wasn't possible to use lambdas in organizers.
88
+
But sometimes we only want a lambda. So we added support.
97
89
98
90
```ruby
99
91
organize LoadOrder, ->(context) { context.order = context.order.decorate }
@@ -160,7 +152,6 @@ class DoSomethingWithOrder
160
152
end
161
153
```
162
154
163
-
164
155
```ruby
165
156
# after
166
157
classOuterOrganizer
@@ -181,7 +172,6 @@ class LoadOrder
181
172
end
182
173
end
183
174
184
-
185
175
classDoSomethingWithOrder
186
176
# ... boilerplate ...
187
177
defcall
@@ -190,7 +180,7 @@ class DoSomethingWithOrder
190
180
end
191
181
```
192
182
193
-
### Conditionals (if/else)
183
+
### Conditionals (if/else) with lambda
194
184
195
185
Along the same lines of each/iteration. We sometimes have to 'break the chain' with interactors just to conditionally call one interactor chain path or another.
No need to manually create a job class or handle the perform/call impedance mismatch
381
369
382
370
```diff
383
-
-SomeInteractor.call!(*args)
384
-
+SomeInteractor::Async.call!(*args)
371
+
-SomeInteractor.call!(*args)
372
+
+SomeInteractor::Async.call!(*args)
385
373
```
386
374
387
375
This also makes it easy to add cron jobs to run interactors. As any interactor can be asyncified.
388
376
By using it's internal Async class.
389
377
390
378
N.B. as your class is now executing asynchronously you can no longer rely on its promises later on in the chain.
391
379
392
-
393
-
394
380
## FAQs
395
381
- This is ugly isn't it?
396
382
@@ -406,59 +392,33 @@ class OuterOrganizer
406
392
)
407
393
end
408
394
```
395
+
1. Do you find the syntax of OuterOrganizer ugly?
409
396
410
-
Yes I agree. It's early days and I'm open to syntax improvement ideas. This is really about it being conceptually less ugly than the alternative, which is to jump around between lots of files. In the existing alternative to using this gem the ugliness is not within each individual file, but within the overall hidden architecture and the hunting process of jumping around in complex interactor chains. We can't see that ugliness but we probably experience it. If you don't feel or experience that ugliness then this gem may not be the right fit for you.
411
-
412
-
413
-
- Is this interactor/interactor-contracts compatible?
414
-
-
415
-
Yes and we use them as dependencies. It's possible we'd drop those dependencies in the future but unlikely. I think it's highly likely we'd retain compatibility.
416
-
417
-
418
-
- Why not propose changes to the interactor or interactor-contracts gem?
419
-
420
-
Honestly, I think both are great and why we've built on top of them.
421
-
I presume they'd object to such an extensive opinionated change, and I think that would be the right decision too.
422
-
If this becomes more stable, less coupled to Rails, there's interest, and things we can provide upstream I'd be happy to propose changes to those gems.
397
+
While the syntax might seem unconventional initially, its conceptual elegance lies in streamlining complex interactor chains. Traditional methods often involve navigating through multiple files, creating a hidden and cumbersome architecture. This gem aims to alleviate that by centralizing operations, making the overall process more intuitive.
423
398
424
-
- Isn't this all just syntactic sugar?
399
+
2. Is this compatible with interactor/interactor-contracts?
425
400
426
-
Yes, but it's sugar that makes the code easier to read and understand.
401
+
Yes, it's fully compatible. We currently use these as dependencies. While there's a possibility of future changes, maintaining this compatibility is a priority.
427
402
428
-
- Is it really easier to parse this new DSL/syntax than POROs?
429
-
430
-
That's subjective, but I think so. The benefit is you have fewer extraneous files patching over a common problem in interactors.
403
+
3. Why not suggest enhancements to the interactor or interactor-contracts gems?
431
404
432
-
- But it gets really verbose and complex!
433
-
434
-
Again this is subjective, but if you've worked with apps with hundred or thousands of interactors, you'll have encountered these problems.
435
-
I think when we work with interactors we're in one of two modes.
436
-
Hunting to find the interactor we need to change, or working on the interactor we need to change.
437
-
This makes the first step much easier.
438
-
The second step has always been a great experience with interactors.
405
+
These gems are excellent in their own right, which is why we've built upon them. Proposing such extensive changes might not align with their current philosophy. However, if our approach proves stable and garners interest, we're open to discussing potential contributions to these gems.
439
406
440
-
- I prefer Service Object
441
-
442
-
If you're not heavily invested into interactors this may not be for you.
443
-
I love the chaining interactors provide.
444
-
I love the contracts.
445
-
I love the simplicity of the interface.
446
-
I love the way they can be composed.
447
-
I love the way they can be tested.
407
+
4. Is this just syntactic sugar?
448
408
449
-
When I've used service objects, I've found them to be more complex to test and compose.
450
-
I can't see a clean way that using service objects to compose interactors could work well without losing some of the aforementioned benefits.
409
+
It's more than that. This approach enhances readability and comprehension of the code. It simplifies the structure, making it easier to navigate and maintain.
451
410
452
-
## Development
411
+
5. Is the new DSL/syntax easier to understand than plain old Ruby objects (POROs)?
453
412
454
-
After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console`for an interactive prompt that will allow you to experiment.
413
+
This is subjective, but we believe it is. It reduces the need for numerous files addressing common interactor issues, thereby streamlining the workflow.
455
414
456
-
To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and the created tag, and push the `.gem` file to [rubygems.org](https://rubygems.org).
415
+
6. Doesn't this approach become verbose and complex in large applications?
457
416
458
-
## Contributing
417
+
While it may appear so, this method shines in large-scale applications with numerous interactors. It simplifies locating and modifying the necessary interactors, which is often a cumbersome process.
459
418
460
-
Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/interactify.
419
+
7. What if I prefer using Service Objects?
461
420
421
+
That's completely valid. Service Objects have their merits, but this gem is particularly useful for those deeply engaged with interactors. It capitalizes on the chaining, contracts, simplicity, composability, and testability that interactors offer. Combining Service Objects with interactors might not retain these advantages as effectively.
462
422
## License
463
423
464
424
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
0 commit comments