Redmine Refactor #126: Convert UsersController to Resource

Today I decided to go ahead and convert UsersController to a REST resource. There were two non-standard methods left (#edit_membership and #destroy_membership) but I can’t see a clear way to refactor them yet. So I just converted the controller to a resource and added those methods as member routes.

Before

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# config/routes.rb
  map.with_options :controller => 'users' do |users|
    users.with_options :conditions => {:method => :get} do |user_views|
      user_views.connect 'users', :action => 'index'
      user_views.connect 'users/:id', :action => 'show', :id => /\d+/
      user_views.connect 'users/new', :action => 'new'
      user_views.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil
    end
    users.with_options :conditions => {:method => :post} do |user_actions|
      user_actions.connect 'users/new', :action => 'create'
      user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
      user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
      user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
    end
    users.connect 'users/:id/edit', :action => 'update', :conditions => {:method => :put}
  end

After

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
# config/routes.rb
  map.with_options :controller => 'users' do |users|
    users.connect 'users/:id/edit/:tab', :action => 'edit', :tab => nil, :conditions => {:method => :get}
 
    users.with_options :conditions => {:method => :post} do |user_actions|
      user_actions.connect 'users/:id/memberships', :action => 'edit_membership'
      user_actions.connect 'users/:id/memberships/:membership_id', :action => 'edit_membership'
      user_actions.connect 'users/:id/memberships/:membership_id/destroy', :action => 'destroy_membership'
    end
  end
 
  map.resources :users, :member => {
    :edit_membership => :post,
    :destroy_membership => :post
  },
  :except => [:destroy]

This conversion wasn’t as clean as I would have hoped but it will be good enough for now. The problems are:

  1. The #edit action needs routes to each of it’s tabs so they can be linked to directly.
  2. #edit_membership and #destroy_membership each have their own custom route underneath Users. Normally these could be refactored to a nested route but…
  3. Redmine already has a MembersController that is used for similar actions as #edit_membership and #destroy_membership. The big difference is that UsersController is an administrator controller while MembersController is a project manager controller. This means there will need to be a bunch of refactoring to merge them.

At the very least, UsersController now has some pretty clear public actions now. Adding a REST API to it should be a lot easier now.

Reference commit