May 30, 2017
This blog is part of our Rails 5.1 series.
When we use method_missing
then we should also use
respond_to_missing?.
Because of this code becomes verbose since both method_missing
and
respond_to_missing?
need to move in tandem.
DHH in the issue itself provided a good example of this verbosity.
class Partition
def initialize(first_event)
@events = [ first_event ]
end
def people
if @events.first.detail.people.any?
@events.collect { |e| Array(e.detail.people) }.flatten.uniq
else
@events.collect(&:creator).uniq
end
end
private
def respond_to_missing?(name, include_private = false)
@events.respond_to?(name, include_private)
end
def method_missing(method, *args, &block)
@events.public_send(method, *args, &block)
end
end
He proposed to use a new method delegate_missing_to
. Here is how it can be
used.
class Partition
delegate_missing_to :@events
def initialize(first_event)
@events = [ first_event ]
end
def people
if @events.first.detail.people.any?
@events.collect { |e| Array(e.detail.people) }.flatten.uniq
else
@events.collect(&:creator).uniq
end
end
end
We at BigBinary have used SimpleDelegator. However one issue with this is that statically we do not know to what object the calls are getting delegated to since at run time the delegator could be anything.
DHH had following to say about this pattern.
I prefer not having to hijack the inheritance tree for such a simple feature.
Delegate method works. However here we need to white list all the methods and in some cases the list can get really long. Following is a real example from a real project.
delegate :browser_status, :browser_stats_present?,
:browser_failed_count, :browser_passed_count,
:sequential_id, :project, :initiation_info,
:test_run, success?,
to: :test_run_browser_stats
Sometimes we just want to delegate all missing methods. In such cases method
delegate_missing_to
does the job neatly. Note that the delegation happens to
only public
methods of the object being delegated to.
Check out the pull request for more details on this.
If this blog was helpful, check out our full blog archive.