# Dry-transaction injection

**URL:** <https://discourse.dry-rb.org/t/dry-transaction-injection/528>\
**Category:** Support\
**Created:** [April 5, 2018, 10:29am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528 "2018-04-05T10:29:59Z")\
**Posts on this page:** 14\
**Page:** 1

<div class="post-metadata">

**Author:** ![xero88](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/xero88/32/247_2.png) [@xero88](https://discourse.dry-rb.org/u/xero88)\
**Post date:** [April 5, 2018, 10:30am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/1 "2018-04-05T10:30:00Z")

</div>

How to inject an object (like a repository) in a transaction ?  
I want to do this, for unit testing the transaction

---

<div class="post-metadata">

**Author:** ![timriley](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/timriley/32/25_2.png) [@timriley](https://discourse.dry-rb.org/u/timriley)\
**Post date:** [April 5, 2018, 11:33am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/2 "2018-04-05T11:33:17Z")

</div>

Hi @xero88, can you please share an example of your transaction class?

---

<div class="post-metadata">

**Author:** ![xero88](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/xero88/32/247_2.png) [@xero88](https://discourse.dry-rb.org/u/xero88)\
**Post date:** [April 5, 2018, 11:47am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/3 "2018-04-05T11:47:22Z")

</div>

For now, here the transaction, that create an article

```
require 'dry-transaction'

class CreateArticle
  include Dry::Transaction

  step :validate
  step :persist

  def initialize(input)
    super(input)
    @repository = MyApp.instance.container['repositories.articles']
  end

  def validate(input)
    validation = ArticleSchema.(input)
    if validation.success?
      Success(input)
    else
      Failure(validation.errors)
    end
  end

  def persist(input)
    article = @repository.create(input)
    Success(article)
  end
end

```

And I call it in the controller :

```
 transaction = CreateArticle.new
      transaction.(article_params) do |result|
        result.success do |article|
          render json: article, status: :created
        end

        result.failure :validate do |errors|
          render json: errors, status: :unprocessable_entity
        end
      end

```

The think that I want to do is to move out of the transaction this part :

> @repository = MyApp.instance.container[‘repositories.articles’]

I want to inject from the controller the repository, something like that :

```
  transaction = CreateArticle.new(repository)

```

---

<div class="post-metadata">

**Author:** ![xero88](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/xero88/32/247_2.png) [@xero88](https://discourse.dry-rb.org/u/xero88)\
**Post date:** [April 9, 2018, 9:28am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/4 "2018-04-09T09:28:56Z")

</div>

I want to do the same as in dry-validation :

`CompanySchema.with(company_repository: @repository).call(input)`

---

<div class="post-metadata">

**Author:** ![timriley](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/timriley/32/25_2.png) [@timriley](https://discourse.dry-rb.org/u/timriley)\
**Post date:** [April 9, 2018, 10:45am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/5 "2018-04-09T10:45:21Z")

</div>

dry-transaction isn’t designed out of the box to automatically handle injection of arbitrary dependencies — it’s designed to help you compose multiple operations to run as steps in a sequence, and it will help you inject those objects.

e.g.

```ruby
class MyTransaction
  step :one_thing
  step :another_thing
end

# inject operation object for "one_thing" step
my_trans = MyTransaction.new(one_thing: -> input { do_something })
my_trans.("input")

```

Now, injecting _other_ things into a transaction object is a different matter. I’ve never tried it myself, which is why I couldn’t give you a quick answer to your questions.

I’ve just looked into it now, and it seems like it’s now possible with the initialize that dry-transaction provides. I’m going to file a couple of issues for this, since it’s something that I would like to make possible, eventually.

Sorry this doesn’t help you in the short term, though.

May I make one suggestion, though? I don’t think you need a transaction in this case. I certainly wouldn’t use one for an object like the one you shared. I think it’s perfectly fine to build up that kind of logic by hand, for example:

```ruby
require "dry-auto_inject"
require "dry-monads"

Import = Dry::AutoInject(MyContainer)

class CreateArticle
  # dry-auto_inject can take care of importing this for you
  include Import[article_repo: "repositories.articles"]

  include Dry::Monads::Result::Mixin

  def call(input)
    validation = ArticleSchema.(input)

    if validation.success?
      article = article_repo.create(validation.to_h)
      Success(article)
    else
      Failure(validation.errors)
    end
  end
end

```

This is exactly like how I build up standard CRUD operation objects in the apps I build. I think it’s more obvious than the transaction approach and will more easily support adding in nuanced operation-specific behaviour in future.

---

<div class="post-metadata">

**Author:** ![timriley](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/timriley/32/25_2.png) [@timriley](https://discourse.dry-rb.org/u/timriley)\
**Post date:** [April 9, 2018, 10:47am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/6 "2018-04-09T10:47:04Z")

</div>

In addition to this: I think the dry-transaction docs need to be reworked to show better examples of the kinds of things that I feel are appropriate for transactions, like piecing together higher-level operations from an application, rather than low-level steps like validate/process/persist, etc. These are hangovers from when I first put the docs together and I haven’t had the time to update them.

---

<div class="post-metadata">

**Author:** ![xero88](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/xero88/32/247_2.png) [@xero88](https://discourse.dry-rb.org/u/xero88)\
**Post date:** [April 9, 2018, 11:04am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/7 "2018-04-09T11:04:05Z")

</div>

Thank you for your answer.

I have an alternative way, I don’t know if this is a good way, but it’s working :

```
  transaction = Company::CreateCompany.new
  transaction.({repository: @repository, input: company_params})

```

I added a step “injection” and injected my repository. Now with that way, I can mock my repository and test my transaction in isolation.

```
class Company::CreateCompany
  include Dry::Transaction

  step :injection
  step :validate
  step :persist

  def injection(input)
    @repository = input[:repository]
    Success(input[:input])
  rescue => e
    Failure(e)
  end

  def validate(input)
     ...
  end

  def persist(input)
    ...
  end
end

```

Do you think this is a good way ? Maybe I can do a new page of the documentation about testing transactions.

---

<div class="post-metadata">

**Author:** ![timriley](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/timriley/32/25_2.png) [@timriley](https://discourse.dry-rb.org/u/timriley)\
**Post date:** [April 9, 2018, 12:00pm UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/8 "2018-04-09T12:00:35Z")

</div>

While that may work for you, I definitely wouldn’t encourage it, because this mixes user data (the `company_params`), which vary at run time, with dependencies (the `repository`) which shouldn’t vary at run time, and should really remain static for the lifetime of the object.

The whole idea behind the functional objects that we encourage is to _separate_ data and behaviour, not to mix them together as `#call` params like you’re doing here.

Mixing them compromises the design of your objects, and will only make them more difficult to understand over time, particularly across the breadth of a full application.

I would really encourage you to look at the second example from my previous reply, and to consider this as the approach for building your simple CRUD operation objects.

---

<div class="post-metadata">

**Author:** ![xero88](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/xero88/32/247_2.png) [@xero88](https://discourse.dry-rb.org/u/xero88)\
**Post date:** [April 9, 2018, 12:15pm UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/9 "2018-04-09T12:15:30Z")

</div>

Ok, I tried your example, it’s seams to work.

And can you provide the rspec test with it ? How mock the repository in your exemple ?

---

<div class="post-metadata">

**Author:** ![xero88](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/xero88/32/247_2.png) [@xero88](https://discourse.dry-rb.org/u/xero88)\
**Post date:** [April 9, 2018, 2:03pm UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/10 "2018-04-09T14:03:58Z")

</div>

Got the response on the gitter :

```
require 'spec_helper'

RSpec.describe Company::CreateCompany, type: :helper do
  let(:company_repository){
    double(CompanyRepository, is_name_available?: true, create: Company.new(nil))
  }

  let(:transaction) { described_class.new(company_repository: company_repository) }

  it 'successful return the entity Company returned by repository' do
    company_input = { name: 'CompanyName', company_type: 'client', legal_form: 'SA' }
    result = transaction.(company_input)

    expect(result.success?).to be(true)
  end

end
```

---

<div class="post-metadata">

**Author:** ![cflipse](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/cflipse/32/248_2.png) [@cflipse](https://discourse.dry-rb.org/u/cflipse)\
**Post date:** [April 10, 2018, 4:33pm UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/11 "2018-04-10T16:33:37Z")

</div>

You can do normal / expected injection, without dropping into using Dry::AutoInject by overriding initialize:

```auto
class CreateArticle
  attr_reader :steps
  def initialiize(repo:, **steps)
    super(steps)
    @repo = repo
  end
end

```

That _should_ get you what I think you’re looking for

---

<div class="post-metadata">

**Author:** ![paul](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/paul/32/202_2.png) [@paul](https://discourse.dry-rb.org/u/paul)\
**Post date:** [May 25, 2018, 5:38pm UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/12 "2018-05-25T17:38:00Z")

</div>

@timriley I’m also anxiously awaiting some better docs and examples for using this library. I came here from Ryan Bigg’s _Exploding Rails_ book, and [he also used](https://github.com/radar/exploding-rails-rom-dry-example-app/blob/master/app/transactions/create_project.rb) the `step :validate; step :persist` pattern.

I really like the declarative “series of steps” to perform, rather than having a long `#call` method with lots “abort early” checks:

```ruby
def call(input)
  return "oops" unless valid?(input)
  params = munge_input(input)
  owner = find_owner(params)
  return "other oops" unless owner
  thing = create_thing(owner, params)
  deliver_notification(owner, thing)
rescue FailedToCreate => ex
  return "some error"
end

```

I like how that can just become:

```auto
check :valid
map :munge 
try :create, catch: FailedToCreate
tee :notify

```

I don’t particularly want to create `Operation`s for each of those, since most of them are actually 3-5 lines of code and not useful or reusable outside this transaction, and that would create more boilerplate LOC to set up the Containers and registration and indirection. (There’s also a lot of friction on my team about including all that, since its such a large departure from the familiar.)

I think I’m probably using transactions in totally the wrong way, since in my mind it is a mechanism to break up a long `#call` and reduce boilerplate. But, from what you’re saying in this thread, how I (and several others) are attempting to use it isn’t how it was intended at all?

---

<div class="post-metadata">

**Author:** ![timriley](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/timriley/32/25_2.png) [@timriley](https://discourse.dry-rb.org/u/timriley)\
**Post date:** [May 30, 2018, 11:10pm UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/13 "2018-05-30T23:10:08Z")

</div>

Hi @paul, that’s a valid use of the library, you should feel free to continue.

---

<div class="post-metadata">

**Author:** ![GustavoCaso](https://yyz1.discourse-cdn.com/flex031/user_avatar/discourse.dry-rb.org/gustavocaso/32/86_2.png) [@GustavoCaso](https://discourse.dry-rb.org/u/GustavoCaso)\
**Post date:** [June 5, 2018, 5:30am UTC](https://discourse.dry-rb.org/t/dry-transaction-injection/528/14 "2018-06-05T05:30:47Z")

</div>

@paul Yep it is an absolutely valid use.

If you want here is an interesting read about `dry-transaction` and `dry-monads` [https://www.morozov.is/2018/05/27/do-notation-ruby.html](https://www.morozov.is/2018/05/27/do-notation-ruby.html)
