Business
Jobs
  • About Us
  • Solutions
    • Job Postings
      Post your job and receive qualified candidates in 48h.
    • Candidate Assessments
      500+ technical and psychological tests, plus anti-fraud.
    • Headhunting
      Tailor-made executive search from start to finish.
    • Payroll + EOR
      Payroll dispersal and EOR across 15+ LATAM countries.
  • Pricing
  • Jobs

0

330
Views
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:

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!

over 4 years ago · Santiago Trujillo
3 answers
Answer question

0

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#throw and Kernel#catch implementation that can be very useful for control flow when navigating through numerous and possibly disparate methods and operations.

The 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(:fail) do
      stop_bad_actor!
      catch(:success) do 
        allow_if_user_is_admin
        allow_if_user_owns_record
        stop_bad_actor!(2)
        allow_for_some_other_reason
        false
      end 
    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 
  
  def stop_bad_actor!(m=1)
    puts "Is a Bad Actor?"
    throw(:fail, false) if @n == 6 || @n ** m == 64
  end
end

Example Output:

PostPolicy.new(1).update 
# Is a Bad Actor?
# Is User Admin?
#=> true
PostPolicy.new(2).update 
# Is a Bad Actor?
# Is User Admin?
# Is User Owner?
#=> true
PostPolicy.new(3).update 
# Is a Bad Actor?
# Is User Admin?
# Is User Owner?
# Is a Bad Actor?
# Is User Special?
#=> true
PostPolicy.new(4).update 
# Is a Bad Actor?
# Is User Admin?
# Is User Owner?
# Is a Bad Actor?
# Is User Special?
#=> false
PostPolicy.new(6).update 
# Is a Bad Actor?
#=> false
PostPolicy.new(8).update 
# Is a Bad Actor?
# Is User Admin?
# Is User Owner?
# Is a Bad Actor?
#=> false
over 4 years ago · Santiago Trujillo Report

0

What you can do is chain && operators.

As soon as one is false, ruby will not evaluate the others (And the update method will return false).

class PostPolicy < ApplicationPolicy

 def update
   allow_if_user_is_admin &&
     allow_if_user_owns_record &&
     allow_for_some_other_reason &&
 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
over 4 years ago · Santiago Trujillo Report

0

It seems that this would achieve your aim and be more idiomatic:

class PostPolicy < ApplicationPolicy

  def update
    user_has_admin_role? ||
      user_owns_object? ||
      some_other_reason?
  end

  private
  
  def user_has_admin_role?
    @user.has_role? :admin
  end

  def user_owns_object?
    @object.owner == user
  end

  def some_other_reason?
    'some other reason'
  end
end
over 4 years ago · Santiago Trujillo Report
Answer question
Find remote jobs

Discover the new way to find a job!

Top jobs
Top job categories
Business
Post vacancy Pricing Sales
Legal
Terms and conditions Privacy policy
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Show me some job opportunities
There's an error!