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.

Methods

create   delete   delete_confirm   index   new   show   update  

Public Instance methods

Create a Project (via ApplicationController.appctrl_create).

[Source]

     # 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.

[Source]

     # File app/controllers/projects_controller.rb, line 166
166:   def delete
167:     appctrl_delete( 'Project' )
168:   end

Show an ‘Are you sure?’ prompt.

[Source]

     # 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.

[Source]

     # 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).

[Source]

     # File app/controllers/projects_controller.rb, line 122
122:   def new
123:     appctrl_new( 'Project' )
124:   end

Show the Project (via ApplicationController.appctrl_show).

[Source]

     # 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.

[Source]

     # 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

[Validate]