I tried DI with Ruby

What is DI

Dependency injection

Avoiding dependencies by allowing objects to be passed to the constructor from the outside

Implementation

I will write using Interactor as an example dry-container and dry-auto_inject I tried DI using

Version without DI

not_di.rb



module Interactor
  class FindUser
    def initialize(params)
      @params = params
    end

    def call
      user_repo = UserRepository.new
      user_repo.by_pk(@params[:id])
    end
  end
end

You can see that it depends on UserRepository

dry-container unused version

pure-di.rb



module Interactor
  class FindUser
    def initialize(params: {}, user_repo: UserRepository.new)
      @params = params
      @user_repo = user_repo
    end

    def call
      @user_repo.by_pk(@params[:id])
    end
  end
end

Initializd arguments tend to be huge and hard to read I have this

dry-container version

dry-di.rb


module Container
  module FindUser
    extend Dry::Container::Mixin

    #Register the object to be injected
    #You can declare a default object with block
    register "params"

    register "user_repo" do
      UserRepository.new
    end
  end
end


module Interactor
  class FindUser
    Import = Dry::AutoInject(Container::FindUser)
    #You will be able to call what you include with method
    include Import["params", "user_repo"]

    def call
      user_repo.by_pk(params[:id])
    end
  end
end

The code has increased, but the outlook has improved by separating the responsibilities.

Because the Interactor depends on the Container, and the caller (such as Controller) also depends on the Container. I was able to reverse the dependence in a nice way

before: controller -> interactor after: controller -> container <- interactor

What makes me happy

--The code is refreshing

Entrusting initialize to container reduces the responsibility of interactor I want to reduce the responsibilities per class

--Unit tests can be done easily

Interactor test can be done without preparing DB In the above example, you can pass an object that reacts to by_pk (id)

test.rb


User = Struct.new(:id, :name, :age)

class TestUserRepo
  def by_pk(id)
    User.new(id, "tarou", 20)
  end
end

params = { id: 1 }
user_repo = TestUserRepo.new
input = { params: params, user_repo: user_repo }

Interactor::FindUser.new(input).call

Can be done like

Recommended Posts

I tried DI with Ruby
I made blackjack with Ruby (I tried using minitest)
I tried UPSERT with PostgreSQL.
I tried BIND with Docker
I tried Jets (ruby serverless)
I tried using JOOQ with Gradle
I tried morphological analysis with MeCab
I tried to interact with Java
I tried UDP communication with Java
I tried GraphQL with Spring Boot
I tried Flyway with Spring Boot
I tried customizing slim with Scaffold
I tried installing Ruby on Rails related plugin with vim-plug
I tried to automate LibreOffice Calc with Ruby + PyCall.rb (Ubuntu 18.04)
I tried to solve the problem of "multi-stage selection" with Ruby
I tried a calendar problem in Ruby
I tried using Realm with Swift UI
I started Ruby
I tried to get started with WebAssembly
I tried using Scalar DL with Docker
I tried using OnlineConverter with SpringBoot + JODConverter
I tried Spring.
I tried time-saving management learning with Studyplus.
I tried playing with BottomNavigationView a little ①
I made a risky die with Ruby
I tried tomcat
I tried using OpenCV with Java + Tomcat
I tried to reimplement Ruby Float (arg, exception: true) with builtin
I tried Lazy Initialization with Spring Boot 2.2.0
I tried youtubeDataApi.
I tried refactoring ①
I tried to build Ruby 3.0.0 from source
I tried FizzBuzz.
I tried to implement ModanShogi with Kinx
I tried JHipster 5.1
[Ruby] I tried to diet the if statement code with the ternary operator
I tried to solve the tribonacci sequence problem in Ruby, with recursion.
I tried to verify AdoptOpenJDK 11 (11.0.2) with Docker image
I tried to make Basic authentication with Java
I tried to manage struts configuration with Coggle
I tried to manage login information with JMX
I implemented Ruby with Ruby (and C) (I played with builtin)
I tried writing CRUD with Rails + Vue + devise_token_auth
I also tried WebAssembly with Nim and C
[Ruby basics] I tried to learn modules (Chapter 1)
I tried Eclipse MicroProfile OpenAPI with WildFly Swarm
I tried to break a block with java (1)
I checked the number of taxis with Ruby
I made a portfolio with Ruby On Rails
I tried Getting Started with Gradle on Heroku
Install Ruby 3.0.0 with asdf
[I tried] Spring tutorial
I tried running Autoware
I tried using Gson
I tried QUARKUS immediately
Getting Started with Ruby
I tried to get the distance from the address string to the nearest station with ruby
I tried using TestNG
I tried Spring Batch
I tried using Galasa
I played with Refinements