a work on process

Viewing posts tagged: ActionView

Within a large project that uses a lot of partials to load in page components, there are a lot of potential points of failure. Add in a developer new to the project, or a front-end developer pressed into service working directly on your views, and the chances of someone editing a partial without realising it’s used in several more places than they’d noticed are fairly high. And if the partial hits an error, the exception will roll all the way up the chain and the end-user will see your 500 page.

Now there are several things that should prevent this from being a problem. Your test coverage should be high enough and run often enough that a page throwing an exception will be noticed very quickly. The partials should be self-contained enough that it doesn’t really matter what context they’re called in. And the project should be well enough documented that a developer can quickly see what dependencies any given piece of code might have.

Every now and again that’s still not enough, or time doesn’t allow you to be quite as consistent as you might want. I’ve run into this particular problem a couple of times, and have just added a solution to one project that I hope will give us a little more protection should the worst happen and a problematic partial makes it into the live environment.

By adding the following code in a file that is loaded from config/environments/production.rb I’m able to trap any exceptions that might occur in a partial, log them, and ensure the worst that happens to a page is a blank space that should have contained content:

module ActionView
  module Partials
 
    private
    def render_and_rescue_partial(partial_path, local_assigns = nil, deprecated_local_assigns = nil) #:nodoc:
      unrescued_render_partial(partial_path, local_assigns, deprecated_local_assigns)
    rescue => err
      # This is where we handle the exception, logging it, emailing, or whatever
      return ''
    end
 
    alias_method :unrescued_render_partial, :render_partial
    alias_method :render_partial, :render_and_rescue_partial
 
  end
end

Basically, it wraps itself around the standard render_partial method, captures any exceptions, handles them, and then returns an empty string. It wouldn’t be hard to extend it to be a little more refined and only capture errors from a certain subset of contexts.

This sort of error handling is a bad idea in a development environment, where you want to see errors as they happen to ensure you’re motivated to fix them. In production, this might help us look a little less foolish if something slips through the net, and let the user see the page they requested.

Recommend this post:

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]

 

Speeding up Rails with erubis

13 February 2007 (5:25 pm)

By James Stewart
Filed under: Notes
Tagged: , , , ,

However much we buy into the adage that hardware is cheaper than developers, we all still need to make our code as responsive as possible. We tune the database, we refactor our code, and try to find the optimum balance between developer time, code legibility, and performance. In the process, many of us have found that rails’ rendering, particularly the Erb library is one of its slowest parts. Enter Erubis.

Erubis is an implementation of eRuby that replaces Erb. It’s written in C and claims to be three times faster than Erb, and 10% faster than its nearest competitor (eruby from mod_ruby which isn’t recommended for use with rails apps). I’ve been trying it out over the past few days, initially with version 2.1 and today with 2.2, and it seemed like time for a report.

Updating an existing rails app is pretty straightforward. I’ve heard that there are some issues to watch out for, but mostly all it takes to convert an existing app is to follow the simple instructions and add:

require 'erubis/helpers/rails_helper'

inside your environment.rb file. Then restart the server, and away you go.

I’ve been testing it out on an app that is fairly early in its lifecycle and hasn’t yet seen much tuning. The app suffers from running too many database queries, but even so it spends more of its time in the rendering than in the database. Running locally off one mongrel I found that, I tested using ‘ab’ from a parallels virtual machine, and found that over 250 requests my standard setup got 7.55 requests/second. Switching to Erubis made little difference to that, which came as quite a surprise.

I then tried applying the patch to rails that the documentation offers as an optional extra. That’s when I saw the real performance leap. Just that change pushed the app up to 13.02 requests/second. I tried it again, and saw 16.29 requests/second. Not quite three times the speed, but doubles not something to be sniffed at. There’s just the small matter of patching rails, which isn’t my first choice as I like to keep this app in step with edge.

But of course this is ruby, so there are alternatives to patching. We can add the new methods in environment.rb before we require the erubis helper and it’ll do the same job.

module ActionView
  class Base
    def convert_template_into_ruby_code(template)
      ERB.new(template, nil, @@erb_trim_mode).src
    end
 
    # Create source code for given template
    def create_template_source(extension, template, render_symbol, locals)
      if template_requires_setup?(extension)
        body = case extension.to_sym
          when :rxml
            "controller.response.content_type ||= 'application/xml'\n" +
            "xml = Builder::XmlMarkup.new(:indent => 2)\n" +
            template
          when :rjs
            "controller.response.content_type ||= 'text/javascript'\n" +
            "update_page do |page|\n#{template}\nend"
        end
      else
        body = convert_template_into_ruby_code(template)
      end
 
      @@template_args[render_symbol] ||= {}
      locals_keys = @@template_args[render_symbol].keys | locals
      @@template_args[render_symbol] = locals_keys.inject({}) { |h, k| h[k] = true; h }
 
      locals_code = ""
      locals_keys.each do |key|
        locals_code < < "#{key} = local_assigns[:#{key}]\n"
      end
 
      "def #{render_symbol}(local_assigns)\n#{locals_code}#{body}\nend"
    end
  end
end

So far, I’m impressed.

Update (17th Feb): I had misread the information and not understood that it is written entirely in ruby. And apparently 2.2 doesn’t have the same issues in rails that 2.1 had.

Recommend this post:

[Slashdot] [Digg] [Reddit] [del.icio.us] [Facebook] [Technorati] [Google] [StumbleUpon]