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,
nly => [: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
August 6, 2007 at 8:04 am
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
August 6, 2007 at 8:28 am
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.
August 6, 2007 at 9:11 am
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!
August 6, 2007 at 10:07 am
[...] DRY Resources Once again, I’ll be responding to one of Marc’s great posts. Today, he’s talking about keeping your controllers DRY, using [...]
August 10, 2007 at 1:57 pm
[...] Colorize your code in your blog posts (with Ruby of course) Published August 10th, 2007 ruby A couple of people asked me how I highlighted my code in a previous post. [...]
August 28, 2007 at 5:28 pm
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
August 28, 2007 at 6:09 pm
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!
April 15, 2009 at 11:54 am
I follow your blog for a long time and must tell you that your articles are always valuable to readers.