Simpler parameter handling for Interactors

Timi Ajiboye
chunks of code*
Published in
2 min readJan 9, 2019

At BuyCoins, we use the Interactor gem for business logic. It works like this:

Say you have an Interactor called SendCoins. You call can trigger it’s functionality by doing

SendCoins.call(amount: 0.5, currency: Ethereum…)

The has passed into #call will be available within the Interactor as attributes of an object called context.

def call
amount = context.amount
end

As your Interactors become more complex and as such accept more parameters, it can become tedious to do this every time for each Interactor.

def call
amount = context.amount
currency = context.currency
address = context.address
… etc etc

The first step to eliminating this annoying repetitiveness was revealed to me by Alessandro Desantis. He realized that the delegate method was perfect.

Delegate is included in ActiveSupport and as such, in every rails application.

It is a pretty simple method but it’s very useful.

delegate :amount, :currency, :address, to: :context

What this does is; whenever amount is called on (or within the interactor), the method call is literally delegated to context and shall return what context.amount returns.

To make it a bit neater, I decided to go a step further.

All our Interactors are subclasses of ApplicationInteractor. There’s some shared logic in that file related to failures and error reporting.

Decided to add this method to it.

def self.parameters(*params)
delegate *params, to: : context
end

This way, in your Interactors, all you need to do is.

parameters: :amount, :currency, :address

Which kind of reminds me of attr_reader.

That’s all folks.

Update (June 8, 2019)

The above code only lets you read the parameters but doesn’t let you write them.

The code below adds to the self.parameters method to make that happen.

def self.parameters(*parameters)
delegate *parameters, to: :context

parameters.each do |parameter|
method_name = "update_#{parameter}"
define_method(method_name) do |new_value|
context.send("#{parameter}=", new_value)
end
end
end

This is a simple bit of metaprogramming that uses define_method to dynamically create update_* methods for every parameter.

Doing this:

parameters: :amount, :currency, :address

Lets you update the values of context.amount, context.currency and context.address like this:

update_amount 0.2
update_currency Bitcoin
update_address "bc1q7tmpy0pqn4mzu02h3ywv7a4t98xdepxgym6tr5"

--

--

Timi Ajiboye
chunks of code*

I make stuff, mostly things that work on computers. Building Gandalf.