1

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.

Cyrus
  • 3,687
  • 5
  • 35
  • 67
  • Strangely, I've catched `NoMethodError` when raising `NameError` exception. Please show us `NoMethodError.superclass` output in the environment – Малъ Скрылевъ Dec 16 '13 at 09:23
  • Interesting ... I'm getting "NoMethodError in Users::Profile#transactions_log" because of "undefined method `display_name' for nil:NilClass" – Cyrus Dec 16 '13 at 09:29
  • I think your should specify something like `rescue NameError, NoMethodError => e`? it'll allow catching `NoMethodError` in a current namespace. – Малъ Скрылевъ Dec 16 '13 at 09:32
  • Good idea. I just tried that, but it didn't work :( – Cyrus Dec 16 '13 at 09:39
  • And just `rescue NoMethodError` placed in additional line? – Малъ Скрылевъ Dec 16 '13 at 09:41
  • Since I have no rails 4, I can only say that you should perform, `grep ` rails for definition of the `def NoMethodError` like `grep NoMethodError /path/to/gems/* -r|grep ".rb:"`, then open found files on-by-one, and see the module in where the class is defined. And put trap in full form like "rescue Module::NoMethodError". If the `NoMethodError` is defined at top-level. There is workaround way to trap. just trap all exception `rescue Exception => e` then use `e.to_s =~ /NoMethodError/` to select it out. – Малъ Скрылевъ Dec 16 '13 at 09:50

2 Answers2

2

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
Simone Carletti
  • 173,507
  • 49
  • 363
  • 364
0

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
spickermann
  • 100,941
  • 9
  • 101
  • 131