def users per_page = Variable::default_pagination_value @users = User.find(:all) # First, check to see if there # was an operation performed if not params[:operation].nil? then if (params[:operation] == "reset_password") then user = User.find(params[:id]) user.generate_password_reset_access_key user.password_confirmation = user.password user.email_confirmation = user.email user.save! flash[:notice] = user.first_name + " " + user.last_name + "'s password has been reset." end if (params[:operation] == "delete_user") then user = User.find(params[:id]) user.item_status = ItemStatus.find_deleted() user.password_confirmation = user.password user.email_confirmation = user.email user.save! flash[:notice] = user.first_name + " " + user.last_name + " has been deleted" end if (params[:operation] == "activate_user") then user = User.find(params[:id]) user.item_status = ItemStatus.find_active() user.password_confirmation = user.password user.email_confirmation = user.email user.save! flash[:notice] = user.first_name + " " + user.last_name + " has been activated" end if (params[:operation] == "show_user") then @user = User.find(params[:id]) render :template => show_user return true end end user_order = 'username' if not params[:user_sort_field].nil? then user_order = params[:user_sort_field] if !session[:user_sort_field].nil? && user_order == session[:user_sort_field] then user_order += " DESC" end session[:user_sort_field] = user_order end @user_pages, @users = paginate(:users, :order => user_order, :conditions => ['item_status_id <> ?', ItemStatus.find_deleted().id], :per_page => per_page) end This AdminController object has a users action. The users action expects an addi- tional parameter, operation, which takes values that determine what functionality occurs within the action. Controller naming is very important, and the name of the controller in this case may indicate a problem. In a RESTful structure, the controller is named for the resource that is being operated on. An AdminController object, then, would be expected to operate on Admins. This is not the case. The following code is the remainder of the controller action, for the sake of clar- ity and thoroughness As you can see, this one action is using the operation parameter to provide the same functionality that would normally be present within the index, show, and destroy actions of a UsersController, as well as additional actions for resetting a user’s pass- word and activating a user, with URLs that looked something like the following: /admin/users?operation=reset_password?id=x /admin/users?operation=delete_user?id=x /admin/users?operation=activate_user?id=x /admin/users?operation=show_user?id=x /admin/users Before we go any further in identifying the changes and solutions to this problem, we need to note the importance of using an automated test suite when making large refactorings like this. If this application didn’t have a test suite (it probably wouldn’t), then it’s recommended that one be written. The most appropriate types of tests would be integration tests using a tool such as Cucumber. These tests allow you to prevent regressions because it should be possible to write the integration tests such that they don’t fail if you haven’t broken anything. This is because integration tests operate on the links that are clicked, the fields that are typed in, and so on, rather than on the internal controller organization of the application. When your integration tests have been addressed, you can refactor the monolithic controller into one or more RESTful controllers. Fortunately, non-RESTful controller actions are very often given the name that your controllers should have. Let’s start by mapping out what the new URLs will be: POST DELETE POST GET GET /admin/users/:id/password /admin/users/:id /admin/users/:id/activation /admin/users/:id /admin/users You need to rename AdminController to UsersController (or create a new one) and create new PasswordsController and ActivationsController objects. Next, you simply take the existing code from the if statements in the existing controller and move it into the corresponding new controller actions: class UsersController < ApplicationController def index per_page = Variable::default_pagination_value user_order = 'username' if not params[:user_sort_field].nil? then user_order = params[:user_sort_field] if !session[:user_sort_field].nil? && user_order == session[:user_sort_field] then user_order += " DESC" end session[:user_sort_field] = user_order end @user_pages, @users = paginate(:users, :order => user_order, :conditions => ['item_status_id <> ?', ItemStatus.find_deleted().id], :per_page => per_page) end def destroy user = User.find(params[:id]) user.item_status = ItemStatus.find_deleted() user.password_confirmation = user.password user.email_confirmation = user.email user.save! flash[:notice] = user.first_name + " " + user.last_name + " has been deleted" end def show @user = User.find(params[:id]) render :template => show_user end end class PasswordsController < ApplicationController def create user = User.find(params[:id]) user.generate_password_reset_access_key user.password_confirmation = user.password user.email_confirmation = user.email user.save! flash[:notice] = user.first_name + " " + user.last_name + "'s password has been reset." end end class ActivationsController < ApplicationController def create user = User.find(params[:id]) user.item_status = ItemStatus.find_active() user.password_confirmation = user.password user.email_confirmation = user.email user.save! flash[:notice] = user.first_name + " " + user.last_name + " has been activated" end end end Now, with functionality organized into these new controllers, the routes for these controllers would be as follows: namespace :admin do resources :users do resource :passwords resource :activations end end As you review this code in more detail, you’re likely to see many other things that could be improved in it. While fixing this example is fairly straightforward, it’s important that you tackle only one issue at a time. You should refactor to a RESTful controller first and then continue improving the code from there. Making a controller RESTful often exposes better improvements and keeps things easier to organize. In addition, by tackling one item at a time, you lessen the risk of getting lost or overwhelmed.