Rails and adapter objects: different implementations in production and tests

Rails and adapter objects: different implementations in production and tests

If you work with service objects in Rails apps, very quickly you need to have the dependency being passed to the service object constructor. Which usually means, that the Rails controller needs to do it. This blogpost describes how to have a different implementation being passed in the production environment and an in-memory one in the tests.

There are several possible solutions, but one could be closer to the hearts of many Rails developers. Let’s just use the built-in Rails environments and configure them appropriately:

$ ag foo_adapter config/environments/
187:  config.foo_adapter     = FooAdapter.new

164:  config.foo_adapter     = FooAdapter.new

184:  config.foo_adapter     = InMemoryFooAdapter.new

As you see, we have the same implementations in the production/dev environments, but a different one in the tests. The tests use an in-memory implementation which probably doesn’t really send the requests to the Foo API.

In the Rails controller, you can then initialize the service object with:

def create

while in the service object you stay unaware of the difference:

class RegisterNewUser
  def initialize(foo_adapter)
    @foo_adapter = foo_adapter

Now, a plug 🔌. Join ARKADEMY.DEV and get access to our best courses: Rails Architect Masterclass, Anti-IF course, Blogging for busy programmers, Async Remote, TDD video class, Domain-Driven Rails video course and growing!

You might also like