Using dry-auto_inject with rails
Around of 2 or 3 months ago, I saw dry-rb at the first time, I thought: “Oh, that’s awesome, I have to experiment”. Today is the day! If you are thinking: “Oh, sorry what is Dry-rb?”. I will explain… Well, Dry-rb is a bunch of tools to simplify and help us to make some code improvements.
Today in this post, I’m going to show how we can use dry-auto_inject with rails. First, There is a simple question, what is dry-auto_inject? According with dry-rb.org, it’s a “Container-agnostic constructor injection mixin”, if you already programmed in languages like Java (Spring @Autowired, says: ‘Hello’), C#, or some language or framework with dependency-injection support you saw the amazing ‘magic’ of Dependency Injection(DI).
If you are thinking: “Oh, my Gosh but I never saw nothing about dependency injection in my life”. Relax, I didn’t forget you. The Internet has a lot of materials about dependency injection. If you read something about SOLID, you already saw this concept. The D in SOLID, represents “Dependency inversion principle”, this principle can be made with an creational pattern, a factory method or a DEPENDENCY INJECTION framework, take a look below.
- Extracted from: https://dzone.com/articles/dependency-injection-0
I won’t explain all details behind this concept, because many people made it as you see below:
If you saw something like the code below, you already had a possibility to use Dry-Auto_Inject:
In this case the class CreateArticle receives a external dependency and calls the repository method(#call). The class CreateArticle believes that ArticleRepository implements a method #call, it doesn’t have any details about repository. If you have some tool to inject the dependency automatically, this code can be more uncoupled and the responsability to know where was implemented, can be delegated to another part of code.
Starting
We have to install the development environment. We will use current stable rails version 5.0.0.1 and ruby 2.3.0. If you don’t have Ruby and Rails installed, check how install in RVM or Rbenv sites, it’s very simple ;).
After that, we can start! To put it into action, we need a Rails application. To create a new App, type the command below. If you already has a Rails app, you can ignore this step.
After create app, we need to install dry-auto_inject. To install, add this line in your Gemfile.
And run
Dry-auto_inject depends of dry-configurable and dry-container. The dry-configurable is “a simple mixin to add thread-safe configuration behaviour to your classes”, you can check here. The dry-container is the core of auto-injection mechanism.
Let’s see how it works.
When someone call Dry::Container#register with the identifier(:article_repository), the dependency is stored inside a proc. After that, when someone call Dry::Container#resolve with identifier(:article_repository) the proc stored previosly is executed or returned. The code inside proc can be executed immediately when resolve the reference or no, let’s see how it works with the code below.
And we can store namespaced identifiers.
For more details, you could check this documentation.
Now, we need to create something to use dry-auto_inject. We will use scaffold to generate the Article model.
Now, we can see the created routes typing ‘rake routes’.
Before run application, we need to create the table to store article entries.
We will change only the article#create route, but be free to modify everything you want. You can create an article to test if everything work as expected, So, open your browser and access http://localhost:3000/articles.
After tests, we can change the code. Take a look at articles_controller.rb.
I will create a command class only for illustration proposes. The command concept here, is very similar of Trailblazer::Operation. If you don’t like it, you can use Article#create to create directly, don’t worry :).
Now, create the folder /commands/article under lib directory, after that, create file create.rb with lines below.
If you run rails console and call Commands::Article::Create#call you will get an error, it’s because we need to add the line responsible to load the created structure at Blog::Application class.
Now you can run rails console and call Commands::Article::Create#call with params. An article is created.
We have to define the container to register all dependencies needed. To reach it, we have to create a file under config/initializers to register dependencies.
Inside this file the constant AutoInject was defined, it will be useful inside ArticlesController to inject dependencies.
To use the registered command, we have to include a reference to the registered dependency. The code will look as below:
Finally, you can test again to see DI working. To see how add tests and many cool things please check the site.
All code is available on my github.
Thanks!
References
- http://dry-rb.org/;
- http://trailblazer.to/gems/operation/1.1/;
- http://www.martinfowler.com/articles/injection.html;
- http://solnic.eu/2013/12/17/the-world-needs-another-post-about-dependency-injection-in-ruby.html;
- https://en.wikipedia.org/wiki/Dependency_inversion_principle.