I'm using Pundit gem for my authorization classes, where each controller action is checked against the model policy, to see if action is allowed by the user.
These methods are sometimes becoming quite bloated and unreadable, because I'm checking quite some stuff for some objects.
Now I'm thinking to refactor those methods, and place every "validation" in it's own method:
Previous:
class PostPolicy < ApplicationPolicy
def update
return true if @user.has_role? :admin
return true if @object.owner == user
return true if 'some other reason'
false
end
end
Now ideally, I want to refactor this in something like:
class PostPolicy < ApplicationPolicy
def update
allow_if_user_is_admin
allow_if_user_owns_record
allow_for_some_other_reason
false
end
private
def allow_if_user_is_admin
# this would go in the parent class, as the logic is the same for other objects
return true if @user.has_role? :admin
end
end
The problem now is, that the mane update method will keep on going, even if the user is admin, as there's no return. If I would inlcude a return, then the other methods will never be evalutaed. Is there a way in ruby to do kind of a "superreturn", so that when the user is an admin, the main update method would stop evaluting?
Thanks!
Given your example and this comment: "...no native way to do kind of a 'super return' in Ruby? It feels like kind of a "raise" but then with a positive outcome... could I use that perhaps?".
While there are usually other ways to solve the issue that could be considered "more idiomatic", ruby does have a
Kernel#throwandKernel#catchimplementation that can be very useful for control flow when navigating through numerous and possibly disparate methods and operations.The
throwand correspondingcatchwill short circuit the result of the block which appears to be the syntax you are looking for.VERY Basic Example:
Example Output: