Resource Controller for “Skinny” Rails Controllers

July 24 2009 by railsdog

These days it seems to be conventional wisdom to build “skinny” controllers in your Rails app. Skinny controllers help you to consolidate your business logic into one place (the model) which allows for easier maintenance and testing. If you’re still not convinced, perhaps you should watch this informative public service announcement.

I’ve been using the excellent resource_controller plugin by James Golick for well over a year now. Its an excellent tool for handling the standard RESTful controller actions that one normally codes by hand (or generator.) We currently use it in the Spree project and yesterday I was curious to compare the size of these controllers to those of a project that does not use resource_controller. First lets look at the results of running rake stats on the Spree project.

spree-stats

As you can see, there are 44 controllers in this project. Yeah, that’s a lot of controllers but Spree is a pretty huge project (its a full featured e-commerce platform.) Now notice that out of 44 classes we only have 111 methods. That’s an average (rounding down) of only 2 methods per class! The methods themselves are also pretty skinny with an average of 8 lines of code per method.

Now lets take a look at Fat Free CRM. I chose this project because it is similar to Spree in that its a full featured platform (not just a little plugin.) DISCLAIMER: I’ve never used this application but I’ve heard good things about it. I’m in no way trying to disparage another person’s work here - I just need a point of comparison.

fat-free-stats

You can see that this project’s controllers are pretty fat. There are only 12 of them but they have more lines of code then in the 44 controllers of Spree. There are 11 methods per controller (compared to 2 in Spree), with the typical method size being the same as Spree. Don’t let the equivalent method size fool you. For instance, take a look at this typical 4 line method in a Spree controller.


create do
  flash nil 
  wants.html {redirect_to edit_order_url(@order)}
end

This is an example of how we override the default resource_controller behavior. In this specific case we did not want to include anything in the flash, nor redirect to show after object creation. If you’re happy with the resource_controller defaults, this method is not even needed.

If you’re interested in a thorough overview of resource_controller, Fabio Akita has produced a very detailed screencast on how it works. Its one of the longest screencasts I’ve ever seen (about 1 hr) but its well worth the time if you’re struggling to wrap your head around how REST works in Rails (both with and without resource_controller.)

Tags:

  • Sean, thanks for running the numbers, it's quite interesting!

    I had considered using the resource_controller, but decided to go with plain REST. My primary reasons: 1) resource_controller seems to hack too deep into Rails internals, so it's a dependency that is likely to cause potential problems with new Rails releases; 2) code clarity -- with plain REST I feel like it's quite clear what's going on; 3) testing -- it's not obvious how you're supposed to write specs when using resource_controller.

    I guess at the end of the day it's a matter of personal taste ;-)
  • @Sohan - We're moving in the direction of adding more unit tests. We recently started using Factory Girl and Shoulda which have eased the burden of writing them. All new features are added with unit tests and we're slowly adding unit tests retroactively as well.
  • I see a bulk of code written in the library. And your models are even skinnier than controllers. I am not sure why, but once we added a service layer in the lib that took care of many business logics. Using this we had skinny controllers, but it was no good. Because the business logic still got split into models and lib, which was difficult to manage/refactor/test.
    Another thing is, the best value of putting business logics in models is not achieved unless unit test is used. I see a very small number of unit tests. Do you follow any other method for testing your business logic?
  • Brian Takita
    @grimen - Funny thing is that rspec relies on standard Ruby subclassing and shoulda does not. Perhaps a new analogy?
  • grimen:
    Maybe inherited_resources looks better but it has a major drawback. It haven't worked for me because of using inheritance.

    I have got common AdminController < ApplicationController scenario which stops me from using this plugin. resource_controller works great. Correct me if I'm wrong and there is a way of using inherited_resources with inherited controllers - I've only played with it for a couple of minutes.
  • Inherited resources sounds interesting. I'll definitely check it out. The rspec to shoulda analogy has me interested (as I just recently made that switch.) I don't think resource_controller was invented just for the sake of inventing a DSL. It solves a major problem for me. That said, I'm always open to a better way of doing things.

    I have no information on the performance of resource_controller. I can't imagine there would be a noticeable difference but I'm only guessing.
  • James H
    How does performance compare on a controller with resource_controller versus explicit method implementations?
  • lolcatz
    Pesonally, I don't like how things are done with resource controller. It's just not obvious.

    My personal thanks to Michael Dvorkin of FFCRM for not using it.
  • I started playing with this back in Feb 08 and have always thought this is how rails should work out of the box. I especially like the haml support. It surprises me that more folks are using this great plugin. Nice writeup.
  • grimen
    I switched from resource_controller to the MUCH better and more Ruby-ish "inherited_resources":

    http://github.com/josevalim/inherited_resources

    resource_controller is for controllers what RSpec is for tests, while inherited_resources is for controllers what Shoulda is for tests. I.e. if you don't like bloated "my little pony"-DSL:s that do magical stuff that's hard to control, I would go with inherited_resources that relies on standard subclassing and no new DSLs but still at least as dry as resource_controller - but makes more sense to a pure Rubyist. That's why I switched, I want to have control and I love the Ruby syntax. Don't invent a new DSL:s just because it's cool to write DSL:s...that's not cool.
blog comments powered by Disqus