DRY-ing your Rails controller with filters

Ever noticed how all CRUD methods on each controller starts with the same line: @item = Model.find(params[:id]) ?

Hey! why not use filter so we don’t repeat ourselves ?

class PostsController < ApplicationController
  before_filter :find_post, :only => [:show, :edit, :update, :destroy]

  def index
    @posts = Post.find(:all)
  end

  def show
  end

  def new
    @post = Post.new
  end

  def edit
  end

  def create
    @post = Post.new(params[:post])

    if @post.save
      flash[:notice] = 'Post was successfully created.'
      redirect_to post_url(@post)
    else
      render :action => "new"
    end
  end

  def update
    if @post.update_attributes(params[:post])
      flash[:notice] = 'Post was successfully updated.'
      redirect_to post_url(@post)
    else
      render :action => "edit"
    end
  end

  def destroy
    @post.destroy

    redirect_to posts_url
  end
  
  private
    def find_post
      @post = Post.find(params[:id])
    end
end

The cool thing about this is, if you decide to switch to using model name in the url, you’ll only have one line to change!

It’s a small step for Rails, but a great step towards honouring the DRY principle:

Every piece of knowledge must have a single, unambiguous, authoritative representation within a system.
– The Programatic Programmer

DRY-fulness we salute you!

8 Comments

Filed under rails, tips

8 responses to “DRY-ing your Rails controller with filters

  1. had a quick look at the link, i think it’s better to use params[:name] directly, ie Model.find_by_name(params[:name]).

    i think site.com/posts/#{id}-#{permalink} is ugly

    of course, you will have to make strings url-safe somewhere, but the result is much better for me

  2. Alain Pilon

    Heri: you cant use “name” unless you are sure that it is going to be unique AND doesnt have any of the forbiden caracters (spaces, comma, etc). If you make your “name” field URL safe, you lose a lot of flexibility in its use. Hence the reason to use permalink.

    Personnaly, I prefer to use:

    site.com/posts/#{permalink}

    when I know that something is going to be unique because it looks better in the URL.

    Another use of the before filter is to know if the user is the owner of the content display in the page when it gives him some special rights. I use something like:

    @owner = @post.user.id == current_user.id ? true : false

    Before filters are great, but when you use more than one, you have to be careful of their order.

  3. I was talking about using site.com/posts/#{permalink} in fact.

    Checkout http://svn.techno-weenie.net/projects/plugins/permalink_fu/ for escaping the permalink field.

    Because if you go with #{id}-#{permalink} you don’t even need to change your finder. to_i will truncate the last part.

    Thanks for the comments and extra tips Heri and Alain!

  4. Pingback: Super DRY Resources « James on Software

  5. Pingback: Colorize your code in your blog posts (with Ruby of course) « Marc-André Cournoyer’s blog

  6. Ikai Lan

    Hey there, one way around making it safe is doing something like a rescue (that is, if you don’t like showing users error pages). I personally prefer using an around filter:

    around_filter :do_something

    protected

    def do_something
    if Model.find_by_name(params[:name]) rescue nil
    yield
    else
    redirect_to :action => :error
    end

    end

  7. Wow, nice tip Ikai, I really like it better then the rescue_action_in_public aproach. I haven’t found any usage for around_filter before.

    Thanks for sharing this!

  8. I follow your blog for a long time and must tell you that your articles are always valuable to readers.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s