So it does appear that the ActionController::Rendering module does include AbstractController::Rendering, which means a call to super in the render method of ActionController::Rendering will in turn call the render method of AbstractController::Rendering. What makes this somewhat confusing is that ActionController::Rendering is included in ActionController::Base, but AbstractController::Rendering is included in ActionController::Base as well. Yet AbstractController::Rendering is also included in ActionController::Rendering. Wouldn't AbstractController::Rendering being included ActionController::Rendering and the fact that ActionController::Rendering is included in ActionController::Base make AbstractController::Rendering being included in ActionController::Base redundant?
On Sep 17, 9:04 pm, John Merlino <stoici...@aol.com> wrote: > In Ruby, classes are never closed: you can always add methods to an > existing class. This applies to the classes you write as well as the > standard, built-in classes. All you have to do is open up a class > definition for an existing class, and the new contents you specify > will be added to whatever's there. In the same regard, if module is > used with the name of a pre-existing module that module is re-opened. > If a method is defined in a re-opened module with the same name as a > pre-existing method in the same module the old method is overwritten > with the new. And, of course, modules can be made immutable, > effectively preventing them from being reopened by freezing the module > object. Frozen modules raise RuntimeErrors when methods are defined, > or variables manipulated, in their context. > > When you include a module in a class, without a prefix (prefix meaning > something like this: AbstractController::Layouts), then ruby searches > for the module of that name within the scope of the current module > wrapping the class that the include was called in. > > So, for example: > > module ActionController > class Base > include Rendering > > Since we "include Rendering" within the scope of the Base class > object, ruby first looksup the constant Rendering, that is, looking > for a module named Rendering in the ActionController namespace, since > that is the namesapce that Base is defined in??? > > Well, ActionController module does define a module named Rendering: > > module ActionController > module Rendering > def render(*args) > raise ::AbstractController::DoubleRenderError if response_body > super > self.content_type ||= Mime[lookup_context.rendered_format].to_s > response_body > end > > So now the method render(*args) is included in the Base class as an > instance method. So when we call, for example, (hypothetically) > ActionView::Base.new.render :action => "my_action", :layout => false, > ActionView::Base is instantiated and we invoke the render instance > method, and since no render method is declared in the Base class > context, ruby scope chain does lookup into the module Rendering and > finds the method so calls it. Now, as you may know, it's possible to > pass multiple kinds of arguments to render, depending on whether you > want to render a template or a partial or file, etc. The * syntax does > the job here, allowing you vary the number of arguments passed. It > checks if there is already a response to the request, and raises an > Exception, if so. Otherwise, it calls super. > > During this super call, I got a little confused. In > ActionController::Base, there is another module included called > AbstractController::Layouts. Layouts in turn includes a module called > Rendering. Since there is a Rendering module within the > AbstractController namespace, it is found, and it indeed contains a > method called render. > > def render(*args, &block) > options = _normalize_render(*args, &block) > self.response_body = render_to_body(options) > end > > And because render is included in Layouts, it's included as an > instance method, and because Layouts was included in > ActionController::Base, that render method utlimately makes its way up > to the Base class. Now we have two modules > (ActionController::Rendering and AbstractController::Rendering that > are including this method into Base. So why doesn't one of them get > overwritten? Why does the call to super work? -- You received this message because you are subscribed to the Google Groups "Ruby on Rails: Talk" group. To post to this group, send email to rubyonrails-talk@googlegroups.com. To unsubscribe from this group, send email to rubyonrails-talk+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/groups/opt_out.