cypriss / mutations

Compose your business logic into commands that sanitize and validate input.

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Is it ok to define private helper methods that use add_error?

OpenCoderX opened this issue · comments

Should we expect execute to halt if helper_method adds_error? Such as:

class ClientActivate < Mutations::Command

  required do
    string :location_uuid, matches: UUID_REGEX
  end

  def validate
    @location = ClientLocation.find_by(uuid: location_uuid)

    if !@location
      add_error(:location_not_found, :not_found, "Location not found")
    end

    @user = User.find_by(uuid: user_uuid)

    if !@user
      add_error(:user_not_found, :not_found, "User not found")
    end
  end

  def execute
    begin
      tx = start_transaction

      @location.status = 1
      @user.generate_timeline_event("Client Location Activation", "Activated Client Location: #{@location.uuid}")
      @location.save
      helper_method # helper method call here
      @location
    rescue StandardError => e
      add_error(:client_location_activate, :final_save, "Client Location activate transaction failed: #{e}")
      tx.failure
    ensure
      tx.close
    end
  end

private

   def helper_method
      add_error()
   end
end

@cypriss are there any best practices around raising errors in helper methods?

I can't really tell what the question is here - could you explain what you expected to happen, what actually happened, and why you believe it's incorrect?

I'm trying to understand the bast practices around calling add_error in helper methods that are themselves called from the execute method. In the docs we recommend this when add_error is used directly in the execute method,

def execute
  if password != password_confirmation
    add_error(:password_confirmation, :doesnt_match, "Your passwords don't match")
    return
  end
end

if condition fails, we call add_error then explicit return but if you call add_error from a helper method the explicit return does not halt execution in the execute method.

I don't think anything is incorrect I just want to read some thoughts on how other users handle calling helper methods from the execute method, do you avoid using add_error in those helper methods if you want to halt execution of the calling execute method.

Should we not do this and instead inline code from helper methods or possible write the helper methods so they do not mutate but rather have the helper methods be more functional then have the execute method evaluate the result of the helper method and only call add_error from execute?

Apologies If I am not clear.

Thanks, I understand now.

I looked through our codebase, which has 897 calls to add_error. The vast majority are inside validate methods, which means they don't need an explicit return.

Most of the others called add_error in a rescue block inside execute:

def execute
  create_a_thing
rescue ActiveRecord::RecordNotUnique
  add_error :thing, :not_unique, "Thing already exists"
end

Some also used the add_error(...); return pattern recommended in the README.

I did find one example of using a helper method in the way you described:

def execute
  helper_method
  return if has_errors?
  # ...
end

def helper_method
  add_error(...)
end

I don't love this approach, since you have to remember to add the has_errors? check.

We could potentially add support for something like throw :halt to allow you to halt the command from inside a helper method but still return an Outcome object to the caller.

@eugeneius your thoughts on this help tremendously, thank you. I'm going to review our codebase and try to standardize the ways in which we raise errors and possibly add some notes in the readme/wiki regarding these strategies.