In Ruby, Can You Decide From A Main Method To Return Or Continue When Calling A Submethod?
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:
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?
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#catch implementation that can be very useful for control flow when navigating through numerous and possibly disparate methods and operations.
throw and corresponding
catch will short circuit the result of the block which appears to be the syntax you are looking for.
VERY Basic Example:
class PostPolicy def initialize(n) @n = n end def update catch(:success) do allow_if_user_is_admin allow_if_user_owns_record allow_for_some_other_reason false end end private def allow_if_user_is_admin puts "Is User Admin?" throw(:success, true) if @n == 1 end def allow_if_user_owns_record puts "Is User Owner?" throw(:success,true) if @n == 2 end def allow_for_some_other_reason puts "Is User Special?" throw(:success,true) if @n == 3 end end
PostPolicy.new(1).update # Is User Admin? #=> true PostPolicy.new(2).update # Is User Admin? # Is User Owner? #=> true PostPolicy.new(3).update # Is User Admin? # Is User Owner? # Is User Special? #=> true PostPolicy.new(4).update # Is User Admin? # Is User Owner? # Is User Special? #=> false
- → Trigger a click with jQuery using link_to of rails 4
- → Adding html data attribute to simple_forms input
- → How to remove parameters from the root URL if it does I18n
- → passing parameters to rails back end from an ajax call
- → Blocking ?page= in robots.txt
- → react js and rails Updating state on a component with active record relationship
- → State not passed into prop
- → Cannot read property 'modalIsOpen' of undefined
- → Objects not valid issue
- → How to map API params to model
- → Consuming webhooks shopify-api
- → How to add ScriptTag on shopify_api gem?