Exit from a Rails Controller

… while inside a method

Stéphane Paquet
2 min readOct 4, 2021

The problem: you have a controller that you want to keep readable. Meaning that part of the logic is lying in private methods. Now, you want to interrupt the code when a certain condition is met from within these methods.

Let’s get hands on!

Assume you have an index method in your controller and that you display different content based on some logic. As previously said, this logic lays in the private methods and to save on CPU you want a simple way to cut short once the conditions are met.

Solution #1: redirect_to and return

class Controller
def index
some_logic and return
# ... more code & logic ...
end

private

def some_logic
unless @user.admin? || @user.owner?
redirect_to edit_user_path(@user) and return true
end

if invalid_user?
redirect_to new_user_path(@user) and return true
end
end
end

Solution #2

We can make the above solution by improving the some_logic method as follow:

class Controller
def index
some_logic and return
# ... more code & logic ...
end

private

def some_logic
unless @user.admin? || @user.owner?
redirect_to edit_user_path(@user) and return
end

if invalid_user?
redirect_to new_user_path(@user) and return
end
return true end
end

(in bold the different between #1 and #2)

You would favor this approach is you already have code in the controller itself that uses redirect_to … and return as you do not need to change these lines, just add a return true at the end of the newly created method.

Solution #3: using a callback block

class Controller
def index
some_logic{ return }
# ... more code & logic ...
end

private

def some_logic
unless @user.admin? || @user.owner?
redirect_to edit_user_path(@user) and yeld
end

if invalid_user?
redirect_to new_user_path(@user) and yeld
end
end
end

that way the inner function can call the “return” block from the outer one and and exit the controller.

So far, we had to introduce changes in the logic… Is there a way to not introduce any change in this part of the code? 🤔

Using the performed? method from ActionController does the job:

Solution #4: ActionController performed?

class Controller
def index
some_logic; return if performed?
# ... more code & logic ...
end

private

def some_logic
unless @user.admin? || @user.owner?
redirect_to edit_user_path(@user) and return
end

if invalid_user?
redirect_to new_user_path(@user) and return
end
end
end

You can see that this approach let you copy the code from your controller index method to a private method without any change at all.

--

--