- Note:
- you can suspend/resume the demo at any time (at completion, you can run it again via the play demo button).
- the representation of inheritance is as per chapter 24 "Classes and Objects" of the Pickaxe
As we have seen in the previous page, the module AC::Helpers (included method) had set up an amazing mechanism: it had hired an Anonymous module, setting a reference to it via the variable master_helper_module in AC::Base.
It had also installed in the metaclass of AC::Base an inherited_with_helper (from now on referred as inherited) method.
Here we will begin to see the reason of such actions; first, to trigger inherited, we will assume that a Request is submitted by the web server to Rails, which subclasses ApplicationController (we will see in another page how that happens).
Thus, inherited is woken up: at first, its actions seem to be the same as what we saw with include: another Anon Module is hired, and a reference to it is set in ApplController.
But then, something else occurs: the new AnonModule is asked to include the previous one! (if you wonder how the method can access the 2 addresses, see discussion in a previous page on class_inheritable_accessors).
And not only that: inherited calls a method which looks for a module whose name is obtained by replacing Controller with Helper: ie, in this case for ApplicationHelper. If found, it is included as well between the Anon Modules!
We will see in a next page how this process will be repeated for every Controller subclassed.
Looking at the resulting diagram, we can notice that the mechanism (which was started with include and continued by inherited) is doing this: building a queue of modules whose names are automatically derived from the Controllers that are being subclassed (of course, we saw only 1, but we got the idea); notice that the Controllers do not access the logic in the modules (they only reference them), unless the programmer adds an include statement (as shown for example in the RailsSpace book, in the UserController). In fact, that chain of modules will be included by the View!
The modules included contain methods designed according to their role: the ApplicationHelper contains methods that will be available to all templates; for this reason in the diagram we showed method logged_in? to indicate a method (which presumably changes the initial page layout based on whether the user is logged in or not) useful to all templates.
One word about the Anonymous Modules; they seem at first just a passive connectivity role (to allow Controllers to hook up the associated Helpers modules), but in fact they also can contain code (how is this possible? the stunning surprises in AC::Helpers and her child ClassMethods have not finished!); we will come back to this later in a new page.
Finally, the code of the method inherited; what took a large quantity of English words (and of pixels in a diagram) to explain is a relatively few lines of Ruby:
def inherited_with_helper(child) inherited_without_helper(child) begin child.master_helper_module = Module.new child.master_helper_module.send :include, master_helper_module child.send :default_helper_module! rescue MissingSourceFile => e raise unless .. end end
- First, remember that the method is activated in the parent of the Controller subclassed; having cleared that, we can see that:
- the parent asks the child to instantiate a Module, and store it in the master_helper_module accessor
- then, the parent asks the child to request the module just created to include the module of its parent (found via the current master_helper_module accessor). [Notice: the sentence sounds a bit strange, as we translated into English the '.' concatenation of method calls. If you read it looking at the statement on the left, it becomes clear]
- finally, the parent asks the child to execute (in Ruby terms, it sends to the child) method default_helper_module!. This method computes the name of the module associated with the controller (ie, in our case, it obtains ApplicationHelper) and then it will (via a call to the helper method) ask the Anon module to include it in the chain of modules.
[URL: ; Last updated: ]
© 2007/10/14 Raul Parolari