The right way to do something you should never do

July 23rd, 2008 by ymendel 2 comments »

One project we’re on now involves a dashboard view that has a continually updating list of items. This seemed like a perfect place to use Juggernaut.

Like with anything else, there was the YAGNI discussion. This could happen with polling and regular AJAX, right? It turns out that not only is pushing with something like Juggernaut more lightweight than polling, it’s easier. There’s no need to contact the server and say “hey, give me everything after this” if you can get an update upon creation.

The trouble is that anything involving Juggernaut seems to smack of MVC violation. It’s obvious that updating a list of items as they come in points to an observer with an after_create callback, but using Juggernaut involves creating some JavaScript by hand or using one of the helpful render calls. So I need a controller. In a model. (Or a model-like thing.)

In accordance with my M.O., I dove into the Rails code and promptly started cursing. Rick, on the other hand, did some searching and came up with a blog post from Matt Harvey. Now, while I’m sure that works, it seemed like way too much. I came up with a different solution.


class LogObserver < ActiveRecord::Observer
  def controller
    returning ActionController::Base.new do |controller|
      controller.instance_variable_set('@template', ActionView::Base.new(ActionController::Base.view_paths))
      controller.instance_variable_set('@assigns', {})
    end
  end

  def after_create(log)
    controller.render :juggernaut do |page|
      page.insert_html :after, 'dashboard_logs_top', :partial => 'logs/log', :locals => { :log => log }
    end
  end
end

I’m not especially proud, but it’s small and it works. And it has specs.

Also, Juggernaut is pretty sweet.

2 Responses to “The right way to do something you should never do”

  1. neilmock Says:

    If you are using something like backgroundrb, which doesn’t implicitly contain the session, you can pass the session_id into the worker, and set it in the controller.

    
    controller.instance_variable_set('@session', CGI::Session::ActiveRecordStore::Session.find_by_session_id(session_id))
    
    
  2. Yossef Says:

    The controller’s @session needs to be set too? Wow, I’m glad this is so easy to use outside of a controller action.

Leave a Reply