The following example will show how, to add an additional RESTful route.
The original controller code example only lists all people:
class TasksController < ApplicationController def index @tasks = Task.all end endand the routes.rb:
resources :tasks, :only => :indexand finally the index.html.erb view:
<table> <thead> <tr> <th>Name</th> <th>Duration</th> </tr> </thead> <tbody> <% @tasks.each do |task| %> <tr> <td><%= task.name %></td> <td><%= task.duration %></td> </tr> <% end %> </tbody> </table>The new requirement is to add a personalized filter to the tasks collection. That's why I add a second action to the controller:
class TasksController < ApplicationController def index @tasks = filter_tasks end def search session[:duration] = params[:duration] @tasks = filter_tasks render :action => :index end private def filter_tasks Task.duration(session[:duration]).all end endThe new search action stores a filter parameter (duration) into the personalized session and finds all tasks depending on their duration. The finder was extracted into the private method (filter_tasks), because the same query is also needed in the index action for consistency reasons.
A model class method (duration) was used as a scoped finder.
Therefore the model:
class Task < ActiveRecords::Base def self.duration duration=nil return scoped if duration.nil? where :duration => duration end endThe search action ends with rendering the same template as the index action.
The next step is to add the custom route into the routes.rb:
resources :tasks, :only => :index do post 'search', :on => :collection endPlease note, the new route is a collection route. It returns a collection of tasks. And it uses the HTTP verb 'POST' for posting the filter parameters to the server.
Doing rake routes in the console:
tasks | GET | /people/:person_id/tasks(.:format) | tasks#index |
search_tasks | POST | /tasks/search(.:format) | tasks#search |
<%= form_tag search_patients_path do %> <%= text_field_tag :duration %> <% end %> <table> <thead> <tr> <th>Name</th> <th>Duration</th> </tr> </thead> <tbody> <% @tasks.each do |task| %> <tr> <td><%= task.name %></td> <td><%= task.duration %></td> </tr> <% end %> </tbody> </table>I admit, sometimes the world is not as simple as examples and tutorials often pretend. That's why there are situations that seem to force you to extend the controller API with a new REStful action. But those cases are rare. Often times there is an option to stick to the 7 standard actions. So always think twice before you want to extend a controller API and always keep the REST approach in mind when doing it, because:
Every additional public method means accepting the responsibility for it.
Supported by Ruby 2.1.1 and Ruby on Rails 3.2.3