Verbose Logging

software development with some really amazing hair

T + G I F R

respond_to With respond_glue: Override respond_to

· · Posted in Programming
Tagged with

So check this: you have a nice little Rails app. You have some stuff for a JSON API type system. You've got an STI setup with the Widget model class and the more concrete FancyWidget and WeirdWidget classes. You've got a WidgetsController, and the corresponding FancyWidgetsController and WeirdWidgetsController

Yay. It works. You can deal with both types of Widgets using JSON.

Now you need an HTML interface to it.

Fine, you can just throw in a format.html in the emit method. Oh wait that won't work. The JSON just returns the same thing all the time, since it has that valid method on there, so if a save fails, valid will be false, and then whatever deals with the JSON can handle when valid is false.

So what to do? Well, you could duplicate the code in emit to all the methods in the WidgetsController and it would probably work out. Then you just do some fun things in the views to generate the right paths (fancy_widget_path instead of widget_path).

But that's no fun. Then you have all this duplicate code, and it's still a pain to override methods in the Fancy and Weird Widget controllers since you can't really call super, since there is that format.html and render call and they don't exactly replace each other. Pain. And Suffering

Who cares, because we have blocks. Tasty ruby blocks that when mixed with anything result in a tasty meal.

So I threw together respond_glue

A little plugin to fix this problem, with minimal crap.

In its simplest form, it's this

This gets included into ActionController::Base, which lets you do stuff like this:

The respond_glue lines setup blocks to be used when calling format.html (or js, xml, whatever. In the example, format.html). The glue_for line sets up the glue for the index action. This must be called after the methods passed in have been defined (so if you want glue_for(:index,:show,:new) then you must call it after defining the index, show and new actions. The superglue_for call sets up the other actions so they run the default superclass action, and actually render.

So what happens when the app hits the index action on the FancyWidgetsController? It's pretty straightforward:

  1. FancyWidgetsController#index gets called
  2. …which is actually defined by the glue_for line
  3. …so the newly defined method calls the original method
  4. …and it calls super
  5. …which calls WidgetsController#index
  6. …which sets up some format handlers
  7. …which returns and continues in FancyWidgetsController#index
  8. …which replaces the html handler originally defined in WidgetsController#index
  9. …which returns, and then the new method (defined by the glue_for) calls the respond_to block

So. You get nice inheritance where you can reuse code in the parent class, and still override the respond_to stuff.

Opinions? Ideas? Did I just do a bunch of work to solve a problem that is better solved another way?

Check out the example here and get the plugin here