Last year I started playing around with using memoized private helper methods in my controllers instead of the traditional instance variable assigns we see in RoR controllers. Here's an example:
class PostsController < ApplicationController
helper_method :new_post, :post, :posts
def new; end
def show; end
def edit; end
def index; end
def create
new_post.attributes = post_params
if new_post.save
redirect_to post
else
render :new
end
end
def update
if post.update_attributes(post_params)
redirect_to post
else
render :edit
end
end
def destroy
post.destroy!
redirect_to :index
end
private
def new_post
@new_post ||= Post.new
end
def post
@post ||= posts.find(params[:id])
end
def posts
@posts ||= current_user.posts
end
def post_params
@post_params ||= params.require(:post).permit(:title, :body)
end
end
Here's what I like about it:
- Actions
#new
,#show
,#edit
,#index
have no unique logic and as such, nothing in their methods (in fact, we don't even have to define methods here but I usually define stub methods to make it clear to readers that those actions do exist) - Actions
#update
,#create
, and#destroy
contain only the logic that is unique and important to them - Avoids hard-to-maintain before_filter
:only
and:except
lists or repetative resource instantiation code - No more "called method on nil" errors. If you misspell something, you'll get an "undefined method" exception which includes your misspelling.
- No more weird ass Rails magic copying ivars from one context to another
I also got into the habit of abstracting the logic in #update
and #create
into another private method (not helper) but I've since stopped doing that because I think it adds more indirection than value. Here's an example of that:
class PostsController < ApplicationController
helper_method :new_post, :post, :posts
def new; end
def show; end
def edit; end
def index; end
def create
save_or_render(:new)
end
def update
save_or_render(:edit)
end
def destroy
post.destroy!
redirect_to :index
end
private
def save_or_render(action)
if post.update_attributes(post_params)
redirect_to post
else
render action
end
end
def new_post
@new_post ||= Post.new
end
def post
@post ||= posts.find(params[:id])
end
def posts
@posts ||= current_user.posts
end
def post_params
@post_params ||= params.require(:post).permit(:title, :body)
end
end
That was really good explaination and thanks for all the code. You've show many unpredictable things..