Recently, I stumbled upon on an unexpected error when i was refactoring my code to follow the style guide of rubocop, Ruby On Rails very own linter.

The and/or style guide recommends that the logical operator && be used in place of and. When I did that, my controllers started to break my tests.

Return JSON Did Not In Fact Return

I have a controller action that looks like this. It does a check on the current user and returns early with a custom json if the condition is right, instead of continuing the propagation to look for the view file corresponding to itself.

def show
  if current_user.one_piece_fan?
    render json: {
      messsage: 'My nakama!'
    } and return

This works fine, but when I changed the and to &&, this custom json was not returned. What went wrong?

&& vs and

There is a very subtle difference between the two. It is their precedence order.

In a line of code consisting of multiple operations, it plays a part in deciding what gets evaluated first. This turns out to be fairly crucial for ruby that has stripped itself of the non-human-friendly characters like brackets and semi-colons. Let’s take a look at the code below.

INSERT IMAGE outputs of && vs and

Did that surprise you?

Well, this is all because of precedence.

In the first line of code, and has a lower precedence than the assignment operator =, hence the assignment took place before the logical AND operation is carried out with false. In other words, this is actually how it looks like had ruby still have its clothes on.

(s = true) && false

Hence, the false value returned from this line of code is referring to the result of the && operation. And when one of the operand is false, the result will be false.

INSERT IMAGE multiply by 0

As for the third line of code, it works just like how most people would commonly interpret it. The result of the && operation is assigned to the s variable, and it subsequent false value is the value that the variable s now holds.

Returning Early In Controllers

So back to the case of controllers.

class ApplicationController < ActionController::API
  def render_and
    render json: {
      message: 'Using "and return"'
    } and return

  def render_amp
    render json: {
      message: 'Using "&& return"'
    } && return

  def render_amp_with_brackets
    render(json: {
      message: 'Using "&& return" with brackets'
    }) && return

Base on the snippet above, the actions render_and and render_amp_with_brackets will work just like how you would have expected. They will return the render function early and stop the controller from propagating further.

As for the render_amp method, it is rendering the result of the && operation between the return function and the hash. Essentially, it looks like this.

render({ ... } && return)

Since there is no eventual return in this render function, the controller will further propagate and carry out its search for the view corresponding the the action.

Final Thoughts

I hope this has help us understand our and and &&s better!

Credits to this stackoverflow answer.

Previous Post
Reopen And Add Methods To Models In Ruby Gems
Next Post
How To Add Datatables To Webpacker In Rails