Handling Multiple Conditions in Ruby using && and == and elsif

Submitted almost 3 years Ago

Share This Post

Recently I needed to take a section of an application with multiple conditions, and add another condition which had a superset of features related to the first condition. There was a few things going on here with && == and elsif so I thought I would lay all this out.

Let me start explaining this with the actual use case.

We started with this:

If a user has the premium subscription plan (Plan B), and they are on this certain signup page, tell them they already have the plan they are viewing.

If a user has any other plan (plan A), prompt them to upgrade to this plan B, as this one they are looking at is the highest level premium plan.

If a user is not registered for a plan, prompt them to get started by signing up for this premium plan, and give them a choice of paying by the month or annually.

The original code looked like this. This is the bottom section of the view page which is in HAML.

(top part of page skipped)
...
    .price-actions
      -  if  user_signed_in?
        - if @user.plan.id == @reserve_plan.id
          .btn.btn-round.btn-primary You Have This Plan
        - else
          .two_button_container
            =link_to  'Upgrade to Reserve Now: Monthly Pay', add_reserve_path, class: 'btn btn-round btn-primary'
            %div.divider
              — or —
            =link_to  'Upgrade to Reserve Now: Annual Pay (Save 20%)', add_reserve_annual_path, class: 'btn btn-round btn-primary'
      - else
        .two_button_container
          = link_to "Get Started: Monthly Pay", new_user_registration_path(plan_id: @reserve_plan.id), :class => 'btn btn-round btn-primary'
          %div.divider
            — or —
          = link_to "Get Started: Annual Pay (Save 20%)", new_user_registration_path(plan_id: @reserve_plan_annual.id), :class => 'btn btn-round btn-primary'

We wanted to get to this:

We had added a new super premium plan C, which had all the previous premium features of plan B, plus the new features. Plan C is a different plan in the application. The user sees both Plan B and Plan C features when they have plan C. So, when they come to the signup page for Plan B, they need to see something different than with other plans, since it is different plan. However, they already have everything included in that plan.

What we wanted was to have these new plan C users, when they were on the plan B page, tell them that their plan already has these features and not let them sign up for Plan B.

That is a quite a bit! ... To summarize how the code needed to be changed:

The original code had these plans:

  1. Not registered

  2. Free plan (Plan A)

  3. Premium Reserve Plan (Plan B), which has feature set A + B

The new code has all these plans:

  1. Not registered

  2. Free plan (Plan A)

  3. Premium Reserve Plan (Plan B)

  4. Super Premium Syrah Plan (Plan C), which has feature set A + B + C

After trying this a few different ways, I modified the code on the Plan B signup page to look like this. It's simpler than the original and provides for the multiple conditions:

(top part of page skipped)
...
    .price-actions
      -  if  user_signed_in? && @user.plan.id == @reserve_plan.id
        .btn.btn-round.btn-primary You Have This Plan
      - elsif user_signed_in? && @user.plan.id == @syrah_plan_monthly.id
        .btn.btn-round.btn-primary Your Plan Already Includes These Features
      - elsif user_signed_in? && @user.plan.id == @free_plan.id
        .two_button_container
          =link_to  'Upgrade to Reserve Now: Monthly Pay', add_reserve_path, class: 'btn btn-round btn-primary'
          %div.divider
            — or —
          =link_to  'Upgrade to Reserve Now: Annual Pay (Save 20%)', add_reserve_annual_path, class: 'btn btn-round btn-primary'
      - else
        .two_button_container
          = link_to "Get Started: Monthly Pay", new_user_registration_path(plan_id: @reserve_plan.id), :class => 'btn btn-round btn-primary'
          %div.divider
            — or —
          = link_to "Get Started: Annual Pay (Save 20%)", new_user_registration_path(plan_id: @reserve_plan_annual.id), :class => 'btn btn-round btn-primary'

Let's dig into what this means and why these were the choices that were made here.

In Ruby, you can check for multiple conditions at the same time with two different operators: && and ||. The "&&" operator, pronounced AND, will look at two conditions at the same time and return true when they are. The "||" operators, pronounced OR, will return true if either condition is met. Clearly in our case here the && was a more straighforward way to write this logic.

Using && versus "and"

In Ruby, && takes higher prececdence than using the word "and". This means that sometimes they will both work correctly but when your code gets more complicated, it may glitch. I've seen experienced people use &&.

Using ==

This checks if the value of two operands are equal or not, if yes then condition becomes true. Remember that everything in Ruby is an object. Since Ruby is a dynamically typed language, different objects can have different definitions for equality.

The Ruby Documentation explains == like this: "At the Object level, == returns true only if obj and other are the same object. Typically, this method is overridden in descendant classes to provide class-specific meaning."

Using Elsif

The "elsif" allows you to do branching in the logic. The elsif and else blocks are considered only if the if test is false. You can have multiple elsif blocks, but only one if and one else block. As you see above the elsif goes in the middle. Note that the correct syntax is "elsif" it is not "elseif". Once you type this 100 times it will start to look normal.

Hope you enjoyed this operators tour.

Share This Post

Like this post? Star it on GitHub

Star It

See All Blog Posts