The maze book for programmers!
mazesforprogrammers.com

Algorithms, circle mazes, hex grids, masking, weaving, braiding, 3D and 4D grids, spheres, and more!

DRM-Free Ebook

The Buckblog

assorted ramblings by Jamis Buck

Extending render

16 January 2007 — 2-minute read

Yesterday’s tip demonstrated how to refactor common RJS bits into their own method. Specifically, it gave an example that created a special render_error method which you can call whenever you need to render an error.

Today’s tip is about overriding the existing render method, to add support for your own custom conditions. Specifically, render_error is nice and all, but wouldn’t it be nice to make it look more like the standard Rails render method?

1
2
3
4
5
def create
  ...
rescue Exception => error
  render :error => error
end

It’s remarkably simple, actually. To implement the above, you’d just throw something like the following in your ApplicationController:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
def render(*args)
  if args.length == 1 && args.first.is_a?(Hash)
    case args.first[:error]
    when nil then super
    when ActiveRecord::InvalidRecord
      render(:update) do |page|
        page[:js_error_bold].replace_html(args.first[:message])
        page[:js_error_text].replace_html(
          args.first[:error].record.errors.full_messages.join("\n"))
        page[:js_error].visual_effect :blind_down, :duration => 0.2
      end
    else raise args.first[:error]
    end
  else
    super
  end
end

In other words, first we check to see if the first and only argument is a hash (since that’s all our new feature uses). Then, we test the value of the :error key, calling super whenever we want to delegate to Rails’ render method. We then compare the error raised to some list of errors that we want to handle specially, and do the appropriate work for each.

You could also make it so that it accepted the error directly, as the first argument (render(error)).

You can use this technique anywhere you find yourself rendering the same kind of thing in multiple places. Errors are a good example, and are (frankly) where I use this technique the most.

Reader Comments

That’s pretty neat. I tend to do a similar thing with find on ActiveRecord:

def self.find(n, opts = {})
  super(n, {:order => 'name'}.merge(opts))
end

Ryan, nifty! Be careful, though, of forcing an order like that, because unless ‘name’ is part of every index you use, your database is going to hate you. ;) Sorting cannot be done efficiently in the database unless the sort key(s) are part of the index that was used to satisfy the query.

Jamis, that is very cool – thanks for the tip a day!

—Zack

Of a somewhat related nature, we created and have been using this plugin:

http://code.inklingmarkets.com/pretty-flash/

If you want to see it in action, just trying and login to http://home.inklingmarkets.com with some random user/pass.

It basically hijacks all uses of flash[:notice] and flash[:error] and throws up a pretty cool box at the bottom (A little green for notices and a little red for errors). It was heavily inspired by the flash notices and errors from Shopify. And I wanted to get it so that it was just an easy drop in plugin without having to change any of my flash[:error] calls to something else.

But it looks like I could make it much niftier and maybe a bit less hackish with this tip.