Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it good practice to use exceptions for control flow in Ruby or Ruby on Rails?

I am reading Agile Web Development with Rails (4th ed.) and I have found the following code

class ApplicationController < ActionController::Base
  protect_from_forgery

  private

  def current_cart
    Cart.find(session[:cart_id])
  rescue ActiveRecord::RecordNotFound
    cart = Cart.create
    session[:cart_id] = cart.id
    cart
  end
end

Since I am a Java developer, my understanding of that part of code is more or less the following:

private Cart currentCard(){
  try{
    return CartManager.get_cart_from_session(cartId)
  }catch(RecordNotFoundEx e){
    Cart c = CartManager.create_cart_and_add_to_session(new Cart())
    return c;    
  }
}

That what strikes me is that the exception handling is used to control normal application flow (lack of Cart is perfectly normal behaviour when user visits Depot application for the first time).

If one takes any Java book, they say that this is a very bad thing to do - and for a good reason: error handling shouldn't be used as a replacement for control statements, it's kind of misleading for those who read code.

Is there any good reason why such a practice is justified in Ruby (Rails)? Is this a common practice in Ruby?

like image 731
Piotr Kochański Avatar asked Jan 19 '11 11:01

Piotr Kochański


People also ask

Should exceptions be used for control flow?

One of these common bad practices is using exceptions as the control flow. This should be avoided for two reasons: It reduces the performance of your code as a response per unit time, and it makes your code less readable.

Does Ruby have exception handling?

Ruby provide a nice mechanism to handle exceptions. We enclose the code that could raise an exception in a begin/end block and use rescue clauses to tell Ruby the types of exceptions we want to handle.

Can we write exceptions in usual flow of program?

Answer: Exceptions are events that disrupt the normal flow of the program. We can handle exceptions in our program and continue with the program normally. An error is an irrecoverable event that cannot be handled and terminates the program.

What are Ruby exceptions?

Exceptions are Ruby's way of dealing with unexpected events. If you've ever made a typo in your code, causing your program to crash with a message like SyntaxError or NoMethodError , then you've seen exceptions in action. When you raise an exception in Ruby, the world stops and your program starts to shut down.


1 Answers

Rails is in no way consistent in its use of exceptions. find will raise an exception if no object is found, but for saving you can choose what behaviour you want. The most common form is this:

if something.save
  # formulate a reply
else
  # formulate an error reply, or redirect back to a form, or whatever
end

i.e. save returns true or false. But there is also save! which raises an exception (adding an exclamation mark to the end of a method name is a Rubyism for showing that a method is "dangerous", or destructive, or simply that it has side-effects, the exact meaning depends on the context).

There is a valid reason for why find raises an exception, though: if a RecordNotFound exception bubbles up to the top level it will trigger the rendering of a 404 page. Since you usually don't catch these exceptions manually (it's rare that you see a rescue ActiveRecord::RecordNotFound in a Rails app), you get this feature for free. In some cases though, you want to do something when an object does not exist, and in those cases you have to catch the exception.

I don't think that the term "best practice" actually means anything, but it is my experience that exceptions aren't used for control of flow in Ruby anymore than in Java or any other language I have used. Given that Ruby doesn't have checked exceptions, you deal with exceptions much less in general.

In the end it's down to interpretation. Since the most common use case for find is retrieving an object to display it, and that the URL for that object will have been generated by the application, it may very well be an exceptional circumstance that the object cannot be found. It means that either the application is generating links to objects that don't exist, or that the user has manually edited the URL. It can also be the case that the object has been removed, but a link to it still exist in a cache, or via a search engine, I would say that that too is an exceptional circumstance.

That argument applies to find when used as in your example, i.e. with an ID. There are other forms of find (including the many find_by_* variants) that actually search, and those don't raise exceptions (and then there is where in Rails 3, which replaces many of the uses of find in Rails 2).

I don't mean to say that using exceptions as control of flow is a good thing to do, just that it's not necessarily wrong that find raises exceptions, and that your particular use case is not the common case.

like image 118
Theo Avatar answered Sep 19 '22 20:09

Theo