Comments (5)
What if we handled interactions like we handle other attributes?
class Interaction < ActiveInteraction::Base
model :account
interaction :access # Access < ActiveInteraction::Base
def execute
access # => returns the result of the interaction
end
end
Interaction.run(account: current_user, access: {a: 1, b: 2})
I was thinking we could call the sub interactions with the same run method used to call the interaction. The data would be passed into Interaction
as a hash called :access
as seen above. We would probably only need to give result
back so that the value inside of execute
is consistent. Errors would be handled the same way we do with hashes (e.g. "Access is invalid."). I haven't thought through all of the issues or use cases but right now I like this direction. Thoughts?
from active_interaction.
At first glance I really liked it, but I think having the sub-interaction explicitly defined in the interaction limits reusability. Now one interaction is tightly coupled to another when it really only needs to care about the type of the result.
For instance:
class DownloadWordsInteraction < ActiveInteraction::Base
string :url
def execute; get_contents(url).split(/\W+/) end
end
class CountWordsInteraction < ActiveInteraction::Base
array :words do
string
end
def execute; count_words(words) end
end
If CountWordsInteraction
was tightly coupled to DownloadWordsInteraction
then I couldn't reuse it if I already had my word list from a file, had downloaded it earlier, or used another interaction that also returns an array of words.
I don't think an interaction implementation should care about composability. Composing interactions should simply be pipelining results from one interaction to another until there is a failure, at which point that failure is returned.
from active_interaction.
The tight coupling is an excellent point. My idea would work well for something like a form that builds more than one model but it definitely falls apart in the case you gave.
from active_interaction.
Definitely good points. What about pulling in already-defined input fields with validations?
As an example, let's look at the account import interaction. https://github.com/orgsync/orgsync/pull/3701/files
There are many potential interactions that make up an operation over a single row in the spreadsheet:
- Create/update user, attaching to default school if not already attached
- Create/update card swipe data for user in school context
- Create/update custom profile information
- Join select portals / groups
- Get added to classifications
Many of these interactions, by themselves, will take some basic information (ie school_id/account_id) that is already known when running the account importer interaction, so maybe there's a middle road we could find. I'm sure there's an API we could come up with that would provide a declarative, composable interface.
class AttachCardInteraction < ActiveInteraction::Base
model :account
model :school
string :card_number
def execute
# ...
end
end
class ImportAccountInteraction < ActiveInteraction::Base
model :account
model :school
# ... many other fields
# not a fan of the names I'm using
interaction :card, class: AttachCardInteraction do
# inherit card number validations/metadata from AttachCardInteraction
inherit_attribute :card_number
use_attribute :account
# or `use_attribute account: :user` if the field is named
# :user in ImportAccountInteraction
use_attribute :school { account.default_school }
# evaluated in the context of the ImportAccountInteraction
# this would be incorrect in this context, but just an idea
end
# perhaps we could make sure all required fields in the specified interaction
# are specified when the interactions are loaded to catch early errors
# another idea to take a sequence of interaction fields
# eg `cards: [{card_number: "1234"}, {card_number: "5678"}]
interactions :cards, class: AttachCardInteraction do
use_attribute :account, :school
inherit_attribute :card_number
end
def execute
# ...
# we'd need to be able to declare whether failures will
# a) halt the process with an error
# b) throw an exception
# c) continue and notify
# d) ignore
#
# also, the order in which these are executed would certainly
# need to be specified in the `execute` method body. all errors
# would bubble up to the top level interaction in a traditional errors
# hash
update_account.execute!
group_memberships.execute_all!
cards.execute_all!
profile_fields.execute_all!
# ...
end
end
This would also allow for better introspection of required sub-fields (vs which are taken care of by the enclosing interaction). What do you guys think?
from active_interaction.
@justinsteffy and I talked this over. We landed on something like this:
ActiveInteraction.pipeline do
run AdditionInteraction, with: { x: 3, y: 5 }
and_then -> (result) { { x: result, y: 7 } }, MultiplicationInteraction
and_then :x, SquareInteraction
no_more_and_then
end
That effectively computes ((3 + 5) * 7) ^ 2
using interactions. Ignoring error handling, it might currently look like this:
outcome1 = AdditionInteraction.run(x: 3, y: 5)
outcome2 = MultiplicationInteraction.run(x: outcome1.result, y: 7)
outcome3 = SquareInteraction.run(x: outcome2.result)
from active_interaction.
Related Issues (20)
- Incorrect filtering of array of hashes in v5? HOT 1
- Activeinteraction::Inputs and ActiveRecord #build_where_clause HOT 1
- Bug: Cached default input values HOT 1
- Question: Would you like to add some hactoberfest labels? HOT 1
- Rails 7: ArgumentError (Could not find or build blob: expected attachable) HOT 1
- An `array` filter can mutate the state of the passed in Array instance
- array :emails is always nil. Why? HOT 2
- Missing some documentation on nested hash default options HOT 4
- `ActiveInteraction::Errors#merge!` does not merge custom options HOT 4
- Input access consistency issues HOT 2
- Something strange with full_messages method for errors HOT 2
- When use callback - compose work strange in interaction HOT 1
- Enum filter HOT 2
- Array Filter with default values aren't initialized on each run HOT 2
- Document typecasting to HashWithIndifferentAccess
- Nested forms HOT 3
- Two datatypes with same variable name HOT 2
- Mongoid::Criteria objects are resolved in object filter HOT 1
- Unexpected validation behavior on filters with validators
- Wrong error message when use hash of array of hashes
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from active_interaction.