Last Updated: February 25, 2016
·
2.35K
· vrinek

ActiveSupport's try does not like Ruby's method_missing

Let's say we have the following code in user.rb to help with authorisation:

def method_missing(method_name, *args, &block)
  if action = method_name[/^can_(.*)\?$/, 1]
    @can_do.include?(action)
  else
    super
  end
end

And we utilise it like that:

if @current_user.try(:can_publish_post?)
  @post.publish!
end

Well... This won't work.

You see, ActiveSupport's try is sending a public method call to the object it is called on only if the object responds to that method. In other words, if we want method_missing and try to play along nicely we need a little more grease in our user.rb:

def respond_to?(method_name, *args, &block)
  method_name =~ /^can_.*\?$/ or super
end

This way, our User model will let others know that it can actually respond to @cat.try(:can_i_haz_cheezburger?).

PS: this is a post-3.2 rails change, it is only on master right now but I stumbled upon it accidentaly and thought to share.

2 Responses
Add your response

Nice catch.

Anyway, what's the point of using try with dynamic method like this?

over 1 year ago ·

@rwz try is always useful when there might be a possibility for the object you call a method on, to be nil (the current_user instance variable in my case). When one builds a Rails app, they usually use a ton of gems and it is usually difficult to know whether a method they use is going through a method_missing or it is declared somewhere and thus the object in question can respond to it.

over 1 year ago ·