Jan 14, 2026

Meet gem Aux

In everyday development, we face the concept of dependency injection. There are different approaches in the Ruby world to implement this design pattern, such as dry-rb. However, on large and complex projects, working with dry-rb turns into torture, especially debugging. That's why I want to introduce you to gem "aux".

Let's say we have a use case for creating a user

class CreateUserUseCase
  include Aux::Pluggable
  include Aux::Carriers

  # Again we register our initialized and memoized CreateUserUseCase.
  # So it will be available as a single instance.
  register initialize: true, memoize: true

  # And here we inject our dependencies.

  # @!attribute [r] user_repository
  #   @return [UserRepository]
  resolve :user_repository, as: :repository

  # @param request [CreateUserRequest]
  # @return [Success, Failure]
  def call(request)
    user = repository.create!(request.to_h)
    success(user) # Create Aux::Carriers::Success instance
  rescue
    failure # Create Aux::Carriers::Failure instance
  end
end
class UserRepository
  include Aux::Pluggable

  # Here we register our initialized and memoized UserRepository.
  # So it will be available as a single instance.
  register initialize: true, memoize: true

  # @!method create!(**criteria)
  #   @param criteria [Hash]
  #   @raise [ActiveRecord::RecordInvalid]
  #   @return [User]
  delegate :create!, to: :data_gateway

  private

  # @return [Class]
  def data_gateway
    @data_gateway ||= User
  end
end

And the CreateUserRequest for example:

class CreateUserRequest
  include Aux::Pluggable
  include Aux::Validations

  # Here we register request as a Class and
  # we can use it later for each given data
  register

  # @!attribute [rw] username
  #   @return [String]
  # @!attribute [rw] email
  #   @return [String]
  attr_accessor :username, :email

  validates :username, presence: true
  validates :email, presence: true, format: { with: /\A[^@\s]+@[^@\s]+\z/ }

  # @param username [String, nil]
  # @param email [String, nil]
  # @return [CreateUserRequest]
  def initialize(username: nil, email: nil)
    @username = username
    @email = email
  end
end

We see 3 interdependent entities that rely on the common dependency registry Aux::Pluggable.registry, where each of them is registered.

UserRepository and CreateUserUseCase are initialized once before registration in the registry. CreateUserRequest registered as a Class and can be initialized for each given datum.

Now we can put it all together in controller.

class UsersController < ApplicationController
  include Aux::Pluggable

  # @!attribute [r] create_request
  #   @return [Class]
  resolve :create_user_request, as: :create_request

  # @!attribute [r] create_use_case
  #   @return [CreateUserUseCase]
  resolve :create_user_use_case, as: :create_use_case

  # POST /users.json
  def create
    request = create_request.new(**params.to_unsafe_h.symbolize_keys)
    return handle_error(request) unless request.valid?

    result = create_use_case.call(request)
    return handle_failure(result) unless result.success?

    render(status: result.code, json: result.payload)
  end
end

That's it. Now, on occasion, we can easily replace a specific implementation such as UserRepository without problems.

These are not all possibilities. There is support for working with namespaces or registering (initializing) objects in the registry directly. The code base of the gem is pretty small and you can read it quickly.