Question

After reading "Practical Object-Oriented Design in Ruby" by Sandi Metz, I decided to use DI in a small service in Ruby (Sinatra or Grape for example).

So far, I have come up with a way to inject dependencies to class variables:

# Service Object
class AppClient
  cattr_accessor :http_client # class variable to be injected

  def self.configure &block # help method to set the class variables
    yield(self)
  end

  def save
    response = http_client.put(url, body: body, params: {}) # use (simplified)
  end
end

# Initializer
AppClient.configure do |config|
  config.http_client = Typhoeus # DI (we inject the dependency here)
end

Do you think this example is a good way to inject dependencies? Do you know other techniques?

Note: I do know that dependency injection is usually unnecessary with Ruby (but this is not the question so is not a duplicated one) Does dependency injection exist in Rails? Ruby dependency injection libraries

Was it helpful?

Solution

Looks fine to me. Classes are objects in Ruby, so dependency injection is just setting a variable at runtime. In your case, you are setting the @http_client instance variable of the AppClient class. Once that variable is accessed by the code that needs the implementation, the class you configured the application with will be returned and it will do the job as long as it responds to the correct messages.

Be careful, though. Remember that classes are singleton objects that are shared within a single Ruby process. Other code could call that accessor method and change that variable as well. This could happen at any point, not just at start up, and will affect all code that uses the implementation. The potential for conflict exists.

This makes this pattern specially unsuitable for use in libraries. Passing the implementation class as a parameter on the call site should be a more robust solution in that case.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top