Sparkle

Description

Cache partials and update them asynchronously after a page renders. Slow method calls happen synchronously as the page renders for the first time. Subsequent page loads retrieve cached objects and render the page quickly, and then Ajax calls can be used to refresh components asynchronously after the page loads.

Usage

Add sparkle to your Gemfile (or whatever if you’re not using bundler):

gem "sparkle"

Include the refreshable module into a class that performs a slow action and tell it what method to execute when refreshing:

class FacebookFeed
  include Sparkle::Refreshable
  sparkle_refresh_method :retrieve_feed

  def initialize(access_token)
    @access_token = access_token
  end

  def retrieve_feed
    # go do something slow
  end
end

Get refreshable objects using the fetch method in your controller or helper methods. Any cache misses will pass the parameters passed to the initializer method of the class:

@facebook_feed = FacebookFeed.sparkle_fetch("some_access_token")

Change calls from render to render_sparkle for partials you want to be refreshed. Note that you cannot use instance variables in any of the refreshable partials, all variables used must be passed as locals:

render_sparkle(:partial => "users/facebook_feed", :locals => { :facebook_feed => @facebook_feed })

When the template is rendered, it will attempt to use a cached version of any objects that include Sparkle::Refreshable. If a cached copy of any local variable is found, a cache key variable called “sparkle_cache_key” will be set. You can use this variable to reference elements of the DOM that should be refreshed (below example in Haml):

- html_options = sparkle_cache_key ? {:id => sparkle_cache_key, :class => "refreshable"} : {}
%div { html_options }
  - facebook_feed.each do |item|
    ...

Add some javascripts to bind the refresh action to DOM elements that need to be refreshed:

$(document).ready(function(){
  $(".refreshable").each(function(index, e) {
    var id = $(e).attr("id");
    $.ajax({
      url: "/sparkle/fetch/" + id,
      success: function(html) {
        $(e).replaceWith(html);
      }
    });
  });
});

Include the controller module into an existing controller in your application:

class ApplicationController < ActionController::Base
  include Sparkle::Controller
  ...

Add a route to config/routes.rb to the fetch action in the controller you included the Sparkle::Controller module in:

map.connect "/sparkle/fetch/:key", :controller => "application", :action => "fetch"

License

The MIT License, see LICENSE