Fetches: Bringing Your ActionController its Slippers

There is a piece of code that shows up more than 80% of the controllers that I write, and it goes a little something like this:

class UsersController < ApplicationController
  def user
    @user ||= User.find(params[:id])
  end
  helper_method :user
end

A simple memoization method to allow me to easily grab the parameter-referred user in all of my actions. If I’m using nested routes, that means I can write two, maybe three of these methods into a controller. I’m basically using slight variations on the same code 20 different times in an application. Since we live in a world that loves to be DRY, I thought, “I can do better.”

Fetches: Memoizing Your Parameter Record Retrieval

Fetches is a simple extension to ActionController that lets you simply define those kinds of fetch methods on a one-line command. For the example above, I can rewrite it like so:

class UsersController < ApplicationController
  fetches :user
end

That’s pretty useful! Not only can I call the “user” method from the controller, but it’s automatically helperized so that I can use the same call in my views. Of course, there are times when more advanced fetching is called for, say using a method other than find or storing to a different variable name. Let’s take a look at a slightly more complex example:

# assuming a route like /users/:user_id/articles/:id
class ArticlesController < ApplicationController
  fetches :user, :as => :author, :from => :user_id, :using => :find_by_login
  fetches :article
end

Now if I were to call “author” in any of my controller actions, it would be equivalent to User.find_by_login(params[:user_id]). Similarly, calling “article” is equivalent to Article.find(params[:id]). The “from” option can also take a Proc in case your fetching is not simply a parameter key:

class UsersController < ApplicationController
  fetches :user, :from => Proc.new{ |c| c.params[:user_id] || c.params[:id] }
end

The main advantages to fetches are brevity, clarity and DRYness. I’ve found that this method covers every use case for parameter-based fetching that I’ve needed, and as such provides a much simpler, more readable, and shorter way to fetch models for use in your controller and views.

Installation

Fetches is available as a gem as well as in traditional plugin format. To install as a gem, add this to your environment.rb:

config.gem 'mbleigh-fetches', :source => 'http://gems.github.com', :lib => "fetches"

To install it as a traditional plugin:

script/plugin install git://github.com/mbleigh/fetches.git

Resources

The source is available on GitHub, the Acts As Community project is there for general discussion, and the Lighthouse is there for bugs and feature suggestions.

UPDATE: A commenter requested that the plugin be able to handle creation of new records in addition to fetching existing records. I have added in the :initialize option to do just this. Examples:

fetches :user, :initialize => true # initialize from params[:user]
fetches :user, :initialize => :author # initialize from params[:author]
fetches :user, :initialize => Proc.new{ |c| {:login => c.params[:login], :email => c.params[:email]} }
Share:

5 Responses to “Fetches: Bringing Your ActionController its Slippers”

  1. Stephen Celis

    I usually DRY up controllers with the following: def user @user ||= if params[:id] User.find params[:id] else User.new params[:user] end end This takes care of the`new` and `create` actions, as well. Your solution is clean; could it take `new_record?`s into account?
  2. Michael Bleigh

    @Stephen: That's a good idea! I don't personally do that most of the time just because there's something I like about being able to see my initialization login in the new and create actions, but there's no reason I can't account for it. Look for an update soon.
  3. Alex

    I found your site on technorati and read a few of your other posts. Keep up the good work. I just added your RSS feed to my Google News Reader. Looking forward to reading more from you down the road!
  4. AlexM

    Your blog is interesting! Keep up the good work!
  5. Jim Gagne

    I can't find "fetches" or "mbleigh-fetches" anywhere on github, including http://gems.github.com/list.html. It's also not on http://agilewebdevelopment.com/plugins. Did you take it down?

Sorry, comments are closed for this article.