Assume we have a list of blog posts. The corresponding controller might look like the following:
class PostsController < ApplicationController
def index
@posts = Post.all.entries
end
# ... other restful actions
end
The routes file would likewise be fairly straightforward:
MyCoolBlog::Application.routes.draw do
resources :posts
end
Everything is fine and well, and completely RESTful. So what happens when we want to introduce an archive feature and provide a route to show all the archived posts?
Let's try to make our index
method smarter. If we have a link to our archived posts somehwere on our site, we could just pass in an archived=true
parameter in the get
request.
# in some ERB template linking to the archived posts
<%= link_to "Archived Posts", posts_path(archived: true) %>
This will create the following URL:
/posts?archived=true
From there, in the index action, we could simply branch on the presence of this parameter.
class PostsController < ApplicationController
def index
if params[:archived] && params[:archived] == true
@posts = Post.where(archived: true).entries
else
@posts = Post.all.entries
end
end
end
The code above works, but leaves something to be desired. So how can we improve it?
Enter collection routes. If we return to our routes file, and create a new collection under the :posts
resources, we'll have the desired behavior without the hacky feeling.
MyCoolBlog::Application.routes.draw do
resources :posts do
collection do
get :archived
end
end
end
By using the above formulation, we now have an archived_posts_path
helper method. The next step is to update our controller:
class PostsController < ApplicationController
def index
@posts = Post.where(archived: false).entries
end
def archived
@posts = Post.where(archived: true).entries
render action: :index
end
end
And voila, we now can create the following link in our ERB template:
<%= link_to "Archived Posts", archived_posts_path %>
The link will generate the following URL: /posts/archived
. And Rails will route the request to our archived
method in the Posts controller which still uses the same template for our regular index.