Dependency injection
Avoiding dependencies by allowing objects to be passed to the constructor from the outside
I will write using Interactor as an example dry-container and dry-auto_inject I tried DI using
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
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-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
--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