ActiveSupport try method and method_missing

Joan R
Joan R
Aug 22, 2017 · 1 min read

Today I was working on a project where there was a class that looked (roughly) like this:

class LazyColor
def initialize(real_color_id, name)
@real_color_id = real_color_id
@name = name
end
def method_missing(method, *args, &block)
if real_color.respond_to?(method)
real_color.public_send(method, *args)
else
super
end
end
attr_reader :real_color_id, :name private def real_color
@real_color ||= Color.find(real_color_id)
end

So, if we send a message to a LazyColor instance and it can’t answer, it will try to use the real_color to respond for it. Let’s see an example:

real_color = Color.create(name: 'red', intensity: 20)
lazy_color = LazyColor.new(real_color.id, name: real_color.name)
puts lazy_color.intensity
=> 10

As you can see, even though lazy_color doesn’t answer to intensity, we were able to get the value from the real_color, because the method_missing implementation of LazyColor delegated to that real_color. Now, imagine a scenario that we don’t know if we are going to have a LazyColor, or a nilvalue, so we want to take advantage of try, like this:

real_color = Color.create(name: 'red', intensity: 10)
lazy_color = LazyColor.new(real_color.id, name: real_color.name)
puts lazy_color.try(:intensity) || 20
=> 20

The reason this gives us 20 is because how try is implemented, it basically invokes the public method of that object itself, without ever going through method_missing.

I found this problem interesting because I have seen many projects where the code has to contemplate nil objects. Specifically in our case, we were doing try just in case instead of a lazy_color we had a nil object. By doing that, we actually caused a regression on how lazy_color handles messages that are not part of its public interface.

)

Semi nerd, amateur cook and I like flossing.

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade