This is the hardest part. In our community convincing people about the benefits of using DI is really hard due to our history with Rails and a very strong criticism of DI with rather ridiculous arguments that it’s not needed because you can monkey-patch. If we took a closer look at the results of monkey-patch-based solutions like Timecop or http-mocking libs, I’m pretty sure we’d clearly see it’s been giving more trouble than actual benefits in testing (brittle tests, unstable tests, less flexibility etc.). With DI you have an explicit way of defining dependencies and the fact it makes testing easier is a nice side-effect of this technique, but it’s not the reason to use it, as the actual reason is the reduction of coupling between individual components of your system.
Another problem is explaining why to use a container. I’ve heard many times an argument that it’s an unnecessary indirection. It surprises me especially when I hear this from really experienced developers. Tight coupling between your code and concrete classes and modules from 3rd party gems has been literally one of the biggest reasons why upgrading apps to newer versions of gems (esp Rails!) could be very difficult. I worked on projects where upgrading to newer version of Rails was practically impossible due to the risk it would bring with upgrading additional gems along with the rails upgrade (classic example: devise).
With a container you are forced to register objects that you’ll be depending on, and it gets you closer to coming up with your own abstractions. Even if you register objects from 3rd party gems without wrapping them in a custom abstraction, you will at least rely on their specific interfaces, once you clearly see what you really need, it’ll be very easy to wrap it with your own abstraction that provides exactly what you need. If it turns out that suddenly a given 3rd party gem is no longer working well for you, you’ll see that your system depends on, ie, mailer service, and it needs one, maybe two methods only, and replacing it is going to be simple. Contrast that with the typical approach where 3rd party code pollutes your entire codebase, it’s especially problematic in large projects, but honestly even on a smaller scale it could be dangerous too.
I believe we’ve come up with a solution that’s lightweight and unobtrusive. I’ve managed to use dry-(container,auto-inject) in a rails project, which was added few months after starting the project. It worked extremely well. If I had another chance to use it in a rails app I would definitely try to create a railtie for dry-component, as it should work even better.