Advanced Rails - Building Industrial-Strength Web Apps in Record Time

(Tuis.) #1

34 | Chapter 1: Foundational Techniques


There is a standard Ruby idiom for chaining methods. Assume we have some library
code that grabs aPerson object from across the network:


class Person
def refresh
# (get data from server)
end
end

This operation takes quite a while, and we would like to time it and log the results.
Leveraging Ruby’s open classes, we can just open up thePersonclass again and
monkeypatch the logging code intorefresh:


class Person
def refresh_with_timing
start_time = Time.now.to_f
retval = refresh_without_timing
end_time = Time.now.to_f
logger.info "Refresh: #{"%.3f" % (end_time-start_time)} s."
retval
end

alias_method :refresh_without_timing, :refresh
alias_method :refresh, :refresh_with_timing
end

We can put this code in a separate file (perhaps alongside other timing code), and, as
long as werequireit after the original definition ofrefresh, the timing code will be
properly added around the original method call. This aids in separation of concerns
because we can separate code into different files based on its functional concern, not
necessarily based on the area that it modifies.


The twoalias_methodcalls patch around the original call torefresh, adding our tim-
ing code. The first call aliases the original method asrefresh_without_timing(giving
us a name by which to call the original method fromrefresh_with_timing); the sec-
ond method pointsrefresh at our new method.


This paradigm of using a twoalias_methodcalls to add a feature is common enough
that it has a name in Rails:alias_method_chain. It takes two arguments: the name of
the original method and the name of the feature.


Usingalias_method_chain, we can now collapse the twoalias_methodcalls into one
simple line:


alias_method_chain :refresh, :timing

Modulization


Monkeypatching affords us a lot of power, but it pollutes the namespace of the patched
class. Things can often be made cleaner by modulizing the additions and inserting the
module in the class’s lookup chain. Tobias Lütke’s Active Merchant Rails plugin uses
this approach for the view helpers. First, a module is created with the helper method:

Free download pdf