AaronLasseigne / active_interaction

:briefcase: Manage application specific business logic.
MIT License
2.05k stars 136 forks source link

Support Procs as a filter #402

Closed ngan closed 7 years ago

ngan commented 7 years ago

Just wondering, has there even been any thoughts on support proc as a filter? e.g.

class Foo < ActiveInteraction::Base
  proc :my_callback, arity: 2
end

Foo.run(my_callback: ->(arg1, arg2) { ... })

I'm finding myself needing it right about now. :-)

tfausak commented 7 years ago

Proc filters aren't built into ActiveInteraction, but there are two ways you can get them.

ActiveInteraction doesn't provide them out of the box because it's designed for use on the web. You can't really send a Proc over the wire.

Checking the arity can be done in a custom validator.

AaronLasseigne commented 7 years ago

In fairness, you can't really send objects or interfaces over the wire either. Like interface, this could be used for dependency injection.

ngan commented 7 years ago

When you say "for use on the web", do you mean to take inputs from only form params?

We've been using interactions for everything and it's been working great. Want to move this model's state from one to another? There's an interaction for that!

Our models are merely for validation and state declarations. Providing an interaction for every task allows us to perform complex operations involving database table locking as well as calling many nested interactions that share the same principles. I wonder how many people are doing the same?

Yes, we do have interactions that take "web inputs" but we quickly coerce or mutate them into proper classes before passing them through to the nested interactions. For example: money is always passed through as an "cents" represented by an Integer. Once we get ahold of that input, the interaction changes it to a Money object before passing it along to other interactions.

If this is completely outside the scope of AI then I can understand that. But if you think AI can possibly go beyond just taking "web inputs" then it opens the door for a lot of cool things like project-custom filters.

tfausak commented 7 years ago

As Aaron pointed out, what I said wasn't accurate.

I'm not opposed to adding a proc filter. Out of curiosity, why are you using Procs instead of compose with another interaction?

ngan commented 7 years ago

I'm using it as a callback. As in, "this interaction requires a callback."

class CreateInvoice < ActiveInteraction::Base
  proc :callback, arity: 1

  def execute
    invoice = Invoice.create(...)

    callback.call(invoice)

    invoice.finalize!
  end
end
AaronLasseigne commented 7 years ago

I think @tfausak was asking why a callback instead of wrapping it in another interaction and composing it in.

ngan commented 7 years ago

Because the callback can be different each time the interaction is executed. Wrapping it in another interaction and composing it would mean hardcoding which interaction is composed, no?

AaronLasseigne commented 7 years ago

Right, you'd have to have a separate wrapping interaction to replace each callback. Can you help us to understand the advantage of the proc over wrapping the interaction? Are there lots of callbacks and it would be tons of work to wrap them all? Does it make the calling code really ugly if each callback case is a separate interaction?

ngan commented 7 years ago

Hey guys, I've just decided to go with object :foo, class: Proc.