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.
Written by Kostas Karachalios
Related protips
2 Responses
Nice catch.
Anyway, what's the point of using try
with dynamic method like this?
@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.