Preferred way to register multiple instances of one class, as opposed to one instance per class

Let’s say you have a hypothetical Repo class, and you want one per database table, something like this:

user_repo = Repo.new(db, :users, has_many: :tweets)
tweet_repo = Repo.new(db, :tweets, has_one: :user)
foo_repo = Repo.new(db, :foos)

And you want each of those to be registered with a container.

Autoloading won’t work, because it expects a unique class per object.

You could just register them all in a file, like app.rb or something:

class App < Dry::Component::Container
  namespace 'repos' do
    register 'user' { Repo.new(resolve('db'), :users, has_many: :tweets) }
    register 'tweet' { Repo.new(resolve('db'), :tweets, has_one: :user) }
    register 'foo' { Repo.new(resolve('db'), :foos) }
  end
end

Is that the preferred way to do this – just one file where you register everything that can’t be autoloaded? Or would you put them into seperate files, and autoload them somehow? Or maybe loop over some config values and create them all that way.

I’m interested to hear your approach.

Yep, manual registration is how we’ve done it for situations like this. You could of course build some loops or whatever to keep the code succinct.

In our dry-web apps, in a sub-app’s boot file, we have something like the following:

require_relative "main/container"

# Load manually registered dependencies
Main::Container.require "component/container/persistence"

Main::Container.finalize! do |container|
  # ...
end

And that component/container/persistence.rb file looks like this:

# Require things we want to work with
require "main/some/object_of_ours"

Main::Container.namespace "main.persistence" do |container|
  container.register "customer_email_uniqueness_check" do
    # build object here
  end
end
1 Like

There’s one small caveat - you gotta move them to a path that’s not part of auto-registration. I don’t think we can easily detect it, but maybe we can? Something to investigate…

1 Like