These are chat archives for dry-rb/chat

6th
May 2018
Jaromír Červenka
@Cervajz
May 06 2018 19:34

Hi guys :) I am learning (and trying to implement) dry-transaction, I am going thru the Introduction and found this:
Each operation shouldn’t accumulate state, instead it should receive an input and return an output without causing any side-effects.

What do you mean by that? Especially this part without causing any side-effects?

I understand that I should not keep some state across operations on the "transaction class" level, but isn't "causing side-effect" a natural outcome of an operation?
Thanks in advance for clarifying
Aaron Barthel
@abrthel
May 06 2018 19:44
Dry-transaction's naming is a bit weird to me but think of it like a process instead of a database transaction. The idea is you create a transaction object that has all the steps needed to handle a process. Then you reuse that transaction object again and again and the only difference is what input you've given it.
So each step would be a pure function that doesn't hold state and acts on the input and returning everything needed in the output
Jaromír Červenka
@Cervajz
May 06 2018 19:45
@abrthel Thanks. so we have the same understanding :c) Input => Output and that's it.
Aaron Barthel
@abrthel
May 06 2018 19:46
as for causing a side effect, well yeah you definitly have to store something to a database or where ever but you don't want your transaction object holding state.
Jaromír Červenka
@Cervajz
May 06 2018 19:46
module ApiTokens
  class Create
    include Dry::Transaction

    step :validate
    step :persist
    step :regenerate_token

    def validate(input)
      validation = ApiTokenSchema.call(input)
      validation.success? ? Success(input) : Failure(validation.errors)
    end

    def persist(input)
      api_token = ApiToken.new(input)
      api_token.save ? Success(api_token) : Failure(api_token.errors)
    end

    def regenerate_token(api_token)
      api_token.regenerate_token!
      Success(api_token)
    end
  end
end
This is my testing class ^^ Should be as you described
The only side-effect is the DB one
Aaron Barthel
@abrthel
May 06 2018 19:46
Seems fine to me
Jaromír Červenka
@Cervajz
May 06 2018 19:47
Thanks! :c)
Aaron Barthel
@abrthel
May 06 2018 19:47
np :smile:
Jaromír Červenka
@Cervajz
May 06 2018 19:48
Is there a way where I could catch failed operations and revert them? Or is that out of the scope?
For example, if the last step would fail, I'd like to delete the record from DB.
Aaron Barthel
@abrthel
May 06 2018 19:50
it's been awhile since I've used dry transaction but I do seem to remember there was a way to handle the failed branch.
As for deleting a record from the DB I imagine a much safer method would be wrapping the transaction in a DB transaction using 'around steps'
Jaromír Červenka
@Cervajz
May 06 2018 19:52
Got it, I am going to look in to that, thanks
Jonah
@jonahx
May 06 2018 19:54
Curious if anyone here has used this gem and, if so, what you thought of it: https://github.com/egonSchiele/contracts.ruby
Aaron Barthel
@abrthel
May 06 2018 19:58
That's ironic, just looked at this gem like 20 minutes ago. Personally I like to do something like https://silkandspinach.net/2011/05/23/contract-tests-in-rspec/ instead of a contracts gem
As well I've gotten alot of mileage out of dry-types as a way to quickly --parse-- validate method inputs along with the idea of guarding the borders of my code and not the hinterlands :)