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
end
and 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
end
The 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
end
The 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
Keine Kommentare:
Kommentar veröffentlichen