Class | ProjectsController |
In: |
app/controllers/projects_controller.rb
|
Parent: | ApplicationController |
File: | projects_controller.rb |
(C): | Hipposoft 2008, 2009 |
Purpose: | Manage Project objects. See models/project.rb for more. |
04-Jan-2008 (ADH): Created.
Create a Project (via ApplicationController.appctrl_create).
# File app/controllers/projects_controller.rb, line 128 128: def create 129: appctrl_create( 'Project' ) 130: end
Projects should not normally be destroyed. Only administrators can do this. Works via ApplicationController.appctrl_delete.
# File app/controllers/projects_controller.rb, line 166 166: def delete 167: appctrl_delete( 'Project' ) 168: end
Show an ‘Are you sure?’ prompt.
# File app/controllers/projects_controller.rb, line 172 172: def delete_confirm 173: return appctrl_not_permitted() unless ( @current_user.admin? ) 174: 175: begin 176: Customer.transaction do 177: destroy_tasks = ! params[ :destroy_tasks ].nil? 178: 179: record = Project.find_by_id( params[ :id ] ) 180: record.destroy_with_side_effects( destroy_tasks ) 181: 182: if ( destroy_tasks ) 183: message = 'Project and its tasks deleted' 184: else 185: message = 'Project deleted; its tasks were left alone' 186: end 187: 188: flash[ :notice ] = message 189: redirect_to( projects_path() ) 190: end 191: 192: rescue => error 193: flash[ :error ] = "Could not destroy project: #{ error }" 194: redirect_to( home_path() ) 195: 196: end 197: end
List projects.
# File app/controllers/projects_controller.rb, line 23 23: def index 24: 25: # Set up the column data; see the index helper functions in 26: # application_helper.rb for details. 27: 28: @columns = [ 29: { :header_text => 'Customer', :sort_by => 'customers.title', :value_helper => :projecthelp_customer }, 30: { :header_text => 'Project title', :value_method => :title, :value_in_place => true }, 31: { :header_text => 'Project code', :value_method => :code, :value_in_place => true }, 32: { :header_text => 'Created at', :value_method => :created_at, :value_helper => :apphelp_created_at }, 33: ] 34: 35: # Get the basic options hash from ApplicationController, then work out 36: # the conditions on objects being fetched, including handling the search 37: # form data. 38: 39: options = appctrl_index_assist( Project ) 40: active_vars = { :active => true } 41: inactive_vars = { :active => false } 42: conditions_sql = "WHERE ( projects.active = :active )\n" 43: 44: # The user may only be able to see projects associated with tasks matching 45: # a specific list of IDs. 46: 47: restrictions_sql = '' 48: 49: if ( @current_user.restricted? ) 50: restrictions_sql = 'INNER JOIN tasks ON ( ' 51: if ( @current_user.task_ids.empty? ) 52: restrictions_sql << 'tasks.id = -1' # Never matches - forces no results 53: else 54: restrictions_sql << "tasks.project_id = projects.id AND tasks.id IN (#{ @current_user.task_ids.join( ',' ) } )" 55: end 56: restrictions_sql << " )\n" 57: end 58: 59: # If asked to search for something, build extra conditions to do so. 60: 61: unless ( params[ :search ].nil? ) 62: if ( params[ :search ].empty? or params[ :search_cancel ] ) 63: params.delete( :search ) 64: else 65: search = "%#{ params[ :search ] }%" # SQL wildcards either side of the search string 66: conditions_sql << "AND ( projects.title ILIKE :search OR projects.code ILIKE :search OR customers.title ILIKE :search )\n" 67: vars = { :search => search } 68: active_vars.merge!( vars ) 69: inactive_vars.merge!( vars ) 70: end 71: end 72: 73: # Sort order is already partially compiled in 'options' from the earlier 74: # call to 'ApplicationController.appctrl_index_assist'. 75: 76: order_sql = "ORDER BY #{ options[ :order ] }" 77: options.delete( :order ) 78: 79: # Compile the main SQL statement. Select all columns of the project, fetching 80: # customers where the project's customer ID matches those customer IDs, with 81: # only projects containing tasks in the user's permitted task list (if any) 82: # are included, returned in the required order. 83: # 84: # Due to restrictions in the way that DISTINCT works, I just cannot figure out 85: # ANY way in SQL to only return unique projects while still matching the task 86: # permitted ID requirement for restricted users. So, fetch duplicates, then 87: # strip them out in Ruby afterwards (ouch). 88: 89: finder_sql = "SELECT projects.* FROM projects\n" << 90: "LEFT OUTER JOIN customers ON ( projects.customer_id = customers.id )\n" << 91: "#{ restrictions_sql }\n" << 92: "#{ conditions_sql }\n" << 93: "#{ order_sql }" 94: 95: # Now paginate using this SQL. The only difference between the active and 96: # inactive cases is the value of the variables passed to Active Record for 97: # substitution into the final SQL query going to the database. 98: 99: @active_projects = Project.paginate_by_sql( [ finder_sql, active_vars ], options ) 100: @inactive_projects = Project.paginate_by_sql( [ finder_sql, inactive_vars ], options ) 101: 102: # Now patch up the deficiencies of the SQL query (see comments above). 103: 104: if ( @current_user.restricted? ) 105: @active_projects.uniq! 106: @inactive_projects.uniq! 107: end 108: end
Show a ‘Create Project’ view (via ApplicationController.appctrl_new).
# File app/controllers/projects_controller.rb, line 122 122: def new 123: appctrl_new( 'Project' ) 124: end
Show the Project (via ApplicationController.appctrl_show).
# File app/controllers/projects_controller.rb, line 116 116: def show 117: appctrl_show( 'Project' ) 118: end
Update the project details. We may need to update associated tasks too, so the update is wrapped in a transaction to allow the database to roll back if anything goes wrong.
@record is set by the "can_be_modified?" before_filter method.
# File app/controllers/projects_controller.rb, line 138 138: def update 139: begin 140: Project.transaction do 141: update_tasks = ! params[ :update_tasks ].nil? 142: 143: @record.update_with_side_effects!( 144: params[ :project ], 145: update_tasks 146: ) 147: 148: flash[ :notice ] = 'Project details updated' 149: redirect_to( projects_path() ) 150: end 151: 152: rescue ActiveRecord::StaleObjectError 153: flash[ :error ] = 'The project details were modified by someone else while you were making changes. Please examine the updated information before editing again.' 154: redirect_to( project_path( @record ) ) 155: 156: rescue => error 157: flash[ :error ] = "Could not update project details: #{ error }" 158: render( :action => 'edit' ) 159: 160: end 161: end