Flattening Nested if-else in Rails Projects

Introduction

I read the article Monads in recurring payment handling by Artur Trzop. I would like to show you how to refactor the solution without increasing the complexity of the code by not using Monads.

Before Refactoring

def create
  if customer_data_valid?
    if customer_created_or_updated_in_payment_system?
      if subscription_created_or_updated_in_payment_system?
        show_success
      else
        show_errors
      end
    else
      show_errors
    end
  else
    show_errors
  end
end

The controller does following things:

  • Validation
  • Payment Processing
  • Subscription

After Refactoring

def create
  customer_data_valid? || render_invalid_data("Invalid data")
  customer_created_or_updated_in_payment_system? || render_payment_error('Payment failed')
  subscription_created_or_updated_in_payment_system? || render_subscription_error('Subscription failed')
end

def render_invalid_data(message)
  @error = message
  render :new and return
end

def render_payment_error(message)
  @error = message
  render :new and return
end

def render_subscription_error(message)
  @error = message
  render :new and return  
end

The refactored version uses Rails trick of rendering and returning immediately in case of an error. The methods such as customer_data_valid?, customer_created_or_updated_in_payment_system? and subscription_created_or_updated_in_payment_system? either returns true for success or returns false if something goes wrong. This makes the code following the || to execute. So, the failure case is handled.


Related Articles


Create your own user feedback survey