An experimental Rails plugin to investigate ways to embed pagelets into standard ActionView templates. The term pagelet is taken from Facebook’s description of their BigPipe infrastructure [1].
WARNING: I’ve never actually used this in a production project, so it may be horribly broken in ways I haven’t figured out yet. If you can provide any evidence it actually works then let me know.
This was built against Rails 2.2.x - 2.3.x is in theory supported but uses a different entry point into ActionController::Base. No idea whether it’s at all usable against any of the 3.0.0 betas.
This is a bit of an experiment to look at different ways of composing larger pages from distinct ‘pagelets’ (or modules, or components, or cells). The key design principles are:
-
Pagelets share little or no state with each other or with the containing page. This makes them easier to reconfigure, if necessary using a language other than Ruby, and encourages good programming.
-
Pagelets have externally meaningful URLs. Again, this makes it possible to refer to them outside of a Rails application.
-
Switching between embedding methods should be a configuration rather than coding change.
Install the plugin, then include the helper module in your app:
module ApplicationHelper include ActionEmbedding::Helpers end
Embed pagelets into your views using something like
<%=embed_pagelet('/pagelets/two', :method => :inline, :send_xhr_header => true) %>
Where /pagelets/two
is a valid route to the content being embedded (i.e. you can access this path externally). The send_xhr_header
option causes the embedded pagelet’s request to include an X-Requested-With: XMLHttpRequest
header, which can be used to make it behave consistently with AJAX loaded content (e.g. by returning a fragment rather than a full HTML document).
There are currently four values for the method
option:
-
:inline
- the pagelet is rendered in the containing Rails process, halting execution of the containing page while it happens. This is the defaul method. -
:proxy
- the pagelet request is proxid to a separate backend HTTP server. Use:proxy_host
to specify the hostname, and the optional:proxy_prefix
to specify a prefix to apply to the path before sending to the backend. -
:esi
- include an<esi:include... >
pseudo-tag at the insertion point so that substitution can be performed in a caching layer supporting Edge Side Includes (e.g. Varnish web accelerator, Akamai edge caching). -
:xhr
- include adiv
with classxhr-replace
and an additionalxhr-href
parameter. Substitution of the correct content can be performed on page load with a small piece of JavaScript, e.g. using jQuery:<script> $(document).ready(function() { $('.xhr-replace').each(function(idx) { $(this).load($(this).attr('xhr-href')); }); }); </script>
In theory the following are possible, but not yet implemented:
-
Multiple pagelets rendered in parallel, blocking at each insertion point until the relevant render job has completed. (Not sure how easy this will be in Rails.)
-
BigPipe style parallel rendering. (See [1]. Again, Rails may be a constraint here both through limits in its ability to handle multiple threads and the difficulty of flushing the output stream before the request has completed.)