Approach on using dry-container and dry-auto_inject on a Rails app


#1

Hello, friends.

First of all, pardon if my question is stupid. I’m not an advanced rubyist and this is my first contact with IoC containers.

I have a Rails app that computes a complex calculation on which I need do forward parameters for many stack levels. So to reduce complexity I’m trying to use a dry-container to register these parameters so they will be resolved using dry-auto_inject inside any layer of the calculation.

This is my container class:

module MyModule
  module Container
    def self.configure(data)
      @container.register :foo, data.foo
      @container.register :bar, data.bar
    end

    @container = Dry::Container.new

    AutoInject = Dry::AutoInject(@container)
  end
end

I’m trying to use this approach on the following calculation:

module MyModule
  class Calculator
    def self.calculate(document)
      Container.configure(document)

      {
        foo: FooCalculator.calculate,
        bar: BarCalculator.calculate,
      }
    end
  end
end

The container would be accessed from my subclasses:

module MyModule
  class FooCalculator
    include Container::AutoInject[:foo]

    def self.calculate
      foo
    end
  end
end
module MyModule
  class FooCalculator
    include Container::AutoInject[:bar]

    def self.calculate
      bar
    end
  end
end

The problem is: it only works the first time. I get the error:

Dry::Container::Error - There is already an item registered with the key "foo"

I understand the container is not dying after my calculation and the next request, when I try to run the algorithm for another document, it gives me this error.

Any tips on how could I create and destroy a container instance and still be able to use dry-auto_inject in subclasses, avoiding to pass the container as a argument to every calculation level?

Is this the correct use-case for using IoC and containers or I’m getting all this very wrong?

Thanks for the help. :slight_smile:


#2

Hi @taschetto, I think you’re right in your hunch that this isn’t a typical usage of a container. Even if you solve the issue of emptying the container before you re-register things (and to do this you’d need to mess around with the container’s internal _container hash, since the public API doesn’t support re-registering), I think there would have to be a better, more fitting solution lying around.

If I were approaching this, I’d go the manual route of passing every argument to every method in your tree of objects, and then work backwards from there to see if things can be made nicer to handle (e.g. maybe creating another object to hold the various args together in a clump?). A good solution would depend a lot on the particulars of your problem, but my feeling is that it would probably never involve an IoC container. I’d mostly try and work with building custom classes and objects.