Home > Enterprise >  Rails pass more than one parameter into dry-monads
Rails pass more than one parameter into dry-monads

Time:12-18

Let's assume I've got below monad class:

require 'dry-monads'
require 'dry/monads/all'

module Test
  class MonadsClass
    include Dry::Monads

    def initialize(signees)
      @signees = signees
    end

    def call
      Success(signees)
        .bind(method(:fetch_template))
        .bind(method(:envelope_from_template))
    end

    attr_reader :signees

    private

    def fetch_template(signees)
      key = "template_#{signees.size}".to_sym
      template_id = Rails.application.credentials.some_api.fetch(key)

      Success(template_id: template_id, key: key)
    end

    def envelope_from_template(template_id:, key:)
      response = some_api.copy_from_template(template_id, key)

      response.failure? ? Failure(response.failure) : Success(response.value!)
    end
  end
end

Why in this combination I'm getting strange error of:

Failure/Error:
def envelope_from_template(template_id:, key:)
  response = some_api.copy_from_template(template_id)

  response.failure? ? Failure(response.failure) : Success(response.value!)
end

ArgumentError:
wrong number of arguments (given 1, expected 0; required keywords: template_id, key)

CodePudding user response:

I think the issue is that you are expecting it to pass kwargs (keyword arguments) but it is passing a Hash. Ruby 2.7 deprecated "automatic conversion" of Hash to kwargs and ruby 3.0 removed it completely. You can read more about the separation of positional and keyword arguments Here

In other words you are expecting it to call

envelope_from_template(template_id: 123, key: 'abc')

but you are actually calling

envelope_from_template({template_id: 123, key: 'abc'})

Instead you have a couple options which should work:

  • Option 1 (call bind with a block)
def call
  Success(signees)
    .bind(method(:fetch_template))
    .bind {|h| envelope_from_template(**h) }
end
  • Option 2 - Change the method signature and then use Hash access methods in the body
def envelope_from_template(params)
  response = some_api.copy_from_template(params.values_at(:template_id, :key))

  response.failure? ? Failure(response.failure) : Success(response.value!)
end
  • Related