Moving Beyond Simple CRUD with RESTful ResourcesProblemContributed by: Diego Scataglini You want to implement a REST API for your web application that goes beyond simple CRUD. For example, you want to add search functionality. SolutionIn this recipe, you'll be creating an interface to search for users. Generate and empty Rails application with the rails command and configure it to access your database. Next, run the scaffold_resource generator to create a User model: $ ruby script/generate scaffold_generator User Now define some fields for the User model: db/migrate/001_create_users.rb: class CreateUsers < ActiveRecord::Migration def self.up create_table :users do |t| t.column :login, :string t.column :email, :string end User.create(:login => "diego", :email => "diego@example.org") User.create(:login => "rob", :email => "rob@example.org") User.create(:login => "chris", :email => "chris@example.org") end def self.down drop_table :users end end Now migrate your database: $ rake db:migrate At this point, you have a wealth of helpers and named routes at your disposal. These can be used anywhere url_for is normally used, including as a parameter to: form_for, redirect_to link_to, link_to_remote, and many other helpers. The named routes produced by the call to map.resources are user_url, users_url, new_user_url, and edit_user_url. To view the generated routes and associated helpers, start the development console: $ ruby script/console development Now, enter the following command: >> puts ActionController::Routing::Routes.draw do |map| ?> map.resources :users >> end.map(&:to_s).sort edit_user_path edit_user_url formatted_edit_user_path formatted_edit_user_url formatted_new_user_path formatted_new_user_url formatted_user_path formatted_user_url formatted_users_path formatted_users_url hash_for_edit_user_path hash_for_edit_user_url hash_for_formatted_edit_user_path hash_for_formatted_edit_user_url hash_for_formatted_new_user_path hash_for_formatted_new_user_url hash_for_formatted_user_path hash_for_formatted_user_url hash_for_formatted_users_path hash_for_formatted_users_url hash_for_new_user_path hash_for_new_user_url hash_for_user_path hash_for_user_url hash_for_users_path hash_for_users_url new_user_path new_user_url user_path user_url users_path users_url Next, modify the route to allow for searching: config/routes.rb: map.resources :users, :collection => {:search => :get} Now the application has a way to search for users. In this case, the relative path /users;search is mapped to the search action in UsersController. Simply define a method called search within the controller: app/controllers/users_controller.rb: def search @users = User.find(:all, :conditions => ["login like ?", "#{params[:q]}%"]) respond_to do |format| format.html { render :action => "index" } format.xml { render :xml => @users.to_xml } end end Lastly, you'll need to modify your view to display users: app/views/users/index.rhtml: <h1>Listing users</h1> <table> <tr> </tr> <% for user in @users %> <tr> <td><%= auto_link(user.email) %></td> <td><%= link_to 'Show', user_path(user) %></td> <td><%= link_to 'Edit', edit_user_path(user) %></td> <td><%= link_to 'Destroy', user_path(user), :confirm => 'Are you sure?', :method => :delete %></td> </tr> <% end %> </table> <br /> <%= link_to 'New user', new_user_path %> To test your new search method, start your development server: $ ruby script/server Finally, navigate to http://localhost:3000/users;search?q=diego. Change the value of the q parameter to find other users. DiscussionRails' RESTful routes support several configuration options, including:
The three most useful options are :collection, :member, and :new. They specify whether the route being defined should be used with collections, a single model, or just the new action, respectively. Each option accepts a single hash parameter that maps actions to HTTP verbs. You can use the option :any if you want an action to respond to any HTTP request method. Test them in your Rails console, and check the available helpers: >> puts ActionController::Routing::Routes.draw do |map| ?> map.resources :users, :new => {:new => :any, :confirm => :put, :save => :post} >> end .map(&:to_s).sort confirm_new_user_path confirm_new_user_url edit_user_path edit_user_url formatted_confirm_new_user_path formatted_confirm_new_user_url formatted_edit_user_path formatted_edit_user_url formatted_new_user_path formatted_new_user_path formatted_new_user_url formatted_new_user_url formatted_save_new_user_path formatted_save_new_user_url ... See Also |