James Golick

James Golick is an engineer, entrepreneur, speaker, and above all else, a grinder.

As CTO (or something?) of BitLove, he scaled FetLife.com's traffic by more than an order of magnitude (and counting).

James spends most of his time writing ruby and scala, building infrastructure, and extinguishing fires.

He speaks regularly at conferences and blogs periodically, but James values shipping code over just about anything else.

Latest Tweets

follow me on Twitter

James on the Web

Introducing resource_controller: Focus on what makes your controller special.

Oct 19 2007

If you're using rails, and you've kept up with what's happening in the community, and in the framework, you're probably writing RESTful apps. You may have noticed, like I did, that most of your controllers follow the same basic pattern - the one that the scaffold_resource (just scaffold in edge/2.0) generator spits out.

I wanted a great way to hide that pattern, and describe the unique features of my controllers through a more domain-specific API. Since I tend to write a lot of nested, and polymorphic resources, I also wanted to DRY up all of that code, and make generating urls a lot more intuitive. Finally, I wanted all of that code to be well-tested, so that I could count on hacking it up when I needed new features, without breaking things.

So, I created it, and here it is.


A basic, out of the generator resource just requires inheriting from ResourceController::Base.
class PostsController < ResourceController::Base  


Before/after callbacks, responses, and flash messages are managed through an extremely flexible API. I tried my best, here, to make syntax succinct when your needs are succinct, and allow API calls to be organized in an intuitive way. What I came up with was a scoping system, where calls to the various API methods can be chained, or scoped with a block.

Take the create action, for example. You might want to add a before block, to assign the author attribute of your post model to the current user.
class PostsController < ResourceController::Base
  create.before do
    @post.author << current_user
As your application matures, you may want to add an RJS response to your create method, for some AJAXy goodness. Easy.
class PostsController < ResourceController::Base
  create.before do
    @post.author << current_user
    response do |wants|
Actually, there's even a shortcut for adding responses. You can omit the response block, if you just want to add responses to what's already provided by resource_controller (just HTML) or has been added elsewhere.
class PostsController < ResourceController::Base
  create do
    before do
      @post.author << current_user
Since I commonly use the same RJS template for several actions, I've found this short-form really handy, because I can use a one-liner to add the same response to several actions.
class PostsController < ResourceController::Base
  [create, update].each { |action| action.wants.js {render :template => "post.rjs"} }
Oh yeah, and you can change the flash too.
class PostsController < ResourceController::Base
  create.flash "Wow! RESTful controllers are so easy with resource_controller!"
For more API details, and examples, see the RDocs.


Helpers are used internally to manage objects, generate urls, and manage parent resource associations.

If you want to customize certain controller behaviour, like member-object, and collection fetching, overriding helper methods is all it takes.

Note:For certain resource_controller functionality to work properly, user-defined helpers must make use of the other r_c helpers. The following examples do not follow that convention for clarity purposes - see the docs for more details.

If you wanted, for example, to use a permalink for your post, you'd need to alter the way that posts are fetched. Just override the object method.
class PostsController < ResourceController::Base
    def object
      @object ||= Post.find_by_permalink(param[:id])
You'll probably also want to add pagination to your index method. In the same way we altered member object fetching, we can change collection fetching behavior.
class PostsController < ResourceController::Base
    def collection
      @collection ||= Post.find(:all, :page => {:size => 10, :current => params[:page]})
Details and examples in the RDocs.

Namespaced Resources

...are handled automatically, and any namespaces are available, symbolized, in array form from the namespaces helper method.

Nested Resources

Again, handled automatically. This can be a real pain, and it's a lot easier with r_c. With an ActiveRecord-like syntax, just say belongs_to :model, and resource_controller takes care of the associations for you.
class CommentsController < ResourceController::Base
  belongs_to :post

Polymorphic Resources

This is a concept that can be found in a lot of my apps. Prior to resource_controller, it was a real pain on various levels. I solved some of my problems with urligence, and took things the rest of the way with resource_controller. It really does pretty much everything for you.

Just use the belongs_to syntax in your controller, and r_c infers whichever association (if any) is present when an action is called. The arguments passed to belongs_to are single possible parents; there is no support for deeply nested resources (although, I'm not necessarily opposed to adding it, if there is demandwe).
class CommentsController < ResourceController::Base
  belongs_to :post, :product
In the above example, the controller will automatically infer the presence of either a parent Post, or Product, and scope all the comments to that parent. The controller will also respond without a parent if you have that in your routes.

Thanks to urligence, generating urls in your polymorphic controller's views is really easy. The object_url, and collection_url helpers will maintain your parent resource's scope automatically.
# /posts/1/comments
object_url          # => /posts/1/comments/#{@comment.to_param}
object_url(comment) # => /posts/1/comments/#{comment.to_param}
edit_object_url     # => /posts/1/comments/#{@comment.to_param}/edit
collection_url      # => /posts/1/comments

# /products/1/comments
object_url          # => /products/1/comments/#{@comment.to_param}
object_url(comment) # => /products/1/comments/#{comment.to_param}
edit_object_url     # => /products/1/comments/#{@comment.to_param}/edit
collection_url      # => /products/1/comments

# /comments
object_url          # => /comments/#{@comment.to_param}
object_url(comment) # => /comments/#{comment.to_param}
edit_object_url     # => /comments/#{@comment.to_param}/edit
collection_url      # => /comments
More in the RDocs.

Getting it

resource_controller is available under the MIT License.

It is currently available in two streams:

1.2.3+ Compatible

Install it:

svn export http://svn.jamesgolick.com/resource_controller/tags/stable vendor/plugins/resource_controller

SVN (stable): http://svn.jamesgolick.com/resource_controller/tags/stable

SVN (ongoing): http://svn.jamesgolick.com/resource_controller/trunk

Note: If you want to run the tests, cd in to the test directory, and type rake test.

Edge/Rails 2.0 Compatible

Install it:

svn export http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable vendor/plugins/resource_controller

SVN (stable): http://svn.jamesgolick.com/resource_controller/tags/edge_compatible/stable

SVN (ongoing): http://svn.jamesgolick.com/resource_controller/branches/edge_compatible

Note: If you want to run the tests in the edge-compatible version, cd in to the test directory, and type rake rails:freeze:edge. I didn't want people to have to download all of edge rails just to get the plugin.

Also, check out the rdoc


Drop me a line and let me know what you think. I'd love to hear your suggestions for API or implementation improvements, or anything else!

Rails polymorphic url generation sucks. Here's something better.

Oct 11 2007

If you've ever written a rails app with a lot of polymorphic resources, you've probably noticed that generating urls for your polymorphic routes is a real pain. In edge rails, some of the problems have been solved by the new polymorphic url methods. Unfortunately, those solutions are both inadequate, and "not recommended for use by end users" (see DHH's comment at the bottom). The problem is that if you want to use the same views and controller code without a lot of ugly conditionals to generate your urls, you're out of luck.

The Problem

## routes.rb

map.resources :photos
map.resources :users, :has_many => :photos
map.resources :tags, :has_many => :photos

## photos_controller.rb

class PhotosController
  ## in the create method
  wants.html { redirect_to url_for(url_helper_params) } # I know DHH doesn't want us to use this, but how else can I get this effect?

  ## in the destroy method
  wants.html { redirect_to photos_url } # unfortunately, this will drop any parent paths we may have
                                        # a user who called DELETE /users/james/photos/1 ends up at /photos instead of /users/james/photos)

    # Note: I actually use a modification to make_resourceful to do this far more cleanly, but wanted to be as complete as possible in this example.
    def parent_object
        when params[:user_id] then User.find_by_id(params[:article_id])
        when params[:tag_id] then Tag.find_by_id(params[:news_id])
    def url_helper_params
      [parent_object, @photo].reject { |obj| obj.nil? } # we have to get rid of any the parent_object if it's nil, or else this will fail :(

# index.rhtml

<%= link_to "New Photo", new_photo_path %> # same problem as our destroy redirect
We have routes like /users/james/photos, and /tags/montrealonrails/photos. We want to seamlessly maintain the top level of the path without resorting to conditionals or repetition. That is, if you browse to /users/james/photos, and click on the show link, you should go to /users/james/photos/1, not /photos/1. There should also be a polymorphic plural url helper. We have url_for for members (/photos/1), but for collections (/photos), we're stuck resorting to calling the url helpers themselves. So, to create a collection url, we'd have to check what the parent object was, and then call the appropriate helper based on that. And, all of this is further complicated when there are namespaces (/cms/products). Wouldn't it be great if there was a better way?

Stupid Simple Urls

Try saying that three times fast. Done? Good, because it's not called that - I was just messing with you.


Intelligent url building.
## routes.rb

map.resources :photos
map.resources :users, :has_many => :photos
map.resources :tags, :has_many => :photos

map.namespace :admin do |admin|
  admin.resources :products, :has_many => :options
  admin.resources :options


assert_equal "/photos", smart_url(:photos)
assert_equal "/photos", smart_url(nil, nil, nil, :photos) # in case your parent objects aren't there
assert_equal "/users/james/photos", smart_url(User.find_by_name(:james), :photos)
assert_equal "/users/james/photos/1", smart_url(User.find_by_name(:james), Photo.find_by_id(1))
assert_equal "/photos/1", smart_url(nil, Photo.find_by_id(1)) # in the case that your parent object isn't there
assert_equal "/photos/1/edit", smart_url(:edit, Photo.find_by_id(1))

assert_equal "/admin/products", smart_url(:admin, :products)
assert_equal "/admin/products/1", smart_url(:admin, Product.find_by_id(1))
assert_equal "/admin/products/1/options", smart_url(:admin, Product.find_by_id(1), :options)
assert_equal "/admin/products/1/edit", smart_url(:edit, :admin, Product.find_by_id(1))
assert_equal "/admin/options", smart_url(:admin, nil, :options) # in the case that your parent object isn't there
It's pretty straightforward. Just call smart_url with any parameters that might be there, including ones that might be nil, and symbols at the beginning for namespaces (simple_url/cms/products), member actions (/products/1/edit), or both (/cms/products/1/edit), objects in the middle, and a symbol at the end for a resource's index method (/products). That's it.

Get It

Get version 0.1 at http://svn.jamesgolick.com/urligence/tags/stable. Oh, and don't take the name of the tag too seriously - I just wrote it tonight.

svn export http://svn.jamesgolick.com/urligence/tags/stable vendor/plugins/urligence

Let me know what you think of it.