Catching exceptions in a render call from a rails helper

1.2k Views Asked by At

This is for a rails 4.0.2 application running ruby 2.0.0-p353.

I have a helper that has the following method

def render_feed_row(activity_item)
  begin
    if activity_item.type == "comment"
      render "newsfeed/comment", :item => activity_item
    elsif activity_item.type == "post"
      render "newsfeed/post", :item => activity_item
    else
      raise NameError
    end
  rescue NameError => e # note: NoMethodError is a subclass of NameError
    render "newsfeed/other", :item => activity_item
  end
end

But if a NoMethodError is raised in the newsfeed/post partial, it is not caught in this helper. Why is that? It don't render newsfeed/other, it actually raises an exception.

2

There are 2 best solutions below

0
Simone Carletti On BEST ANSWER

I've just checked with a simplified version of your code, and it worked correctly.

def render_feed_row
  raise NoMethodError
rescue NameError
  puts "kaboom"
end

render_feed_row
# => kaboom

However, please note it's a very bad practice to use exceptions for control flow in such way. Moreover, if you really want to use exceptions, you should create your own classes, not use NoMethodError or NameError that have specific meanings in Ruby programs.

Here's a more clean version of your method

def render_feed_row(activity_item)
  case (type = activity_item.type)
  when "comment", "post"
    render "newsfeed/#{type}", item: activity_item
  else
    render "newsfeed/other", item: activity_item
  end
end

Or a more concise version

def render_feed_row(activity_item)
  name = case activity_item.type
  when "comment", "post"
    activity_item.type
  else
    "other"
  end
  render "newsfeed/#{name}", item: activity_item
end
0
spickermann On

Using exceptions for control flow is slow. Why not just:

def render_feed_row(activity_item)
  partial = ['comment', 'post'].include?(activity_item.type) ? 
                                                    activity_item.type : 'other'

  render "newsfeed/#{partial}", :item => activity_item
end