1 class RunLoggerController < ApplicationController 2 3 # NOTE: These classes are huge, but only because they are 80% comments. Normally, 4 # there isn't much too controllers. Each action method is usually pretty compact. 5 6 # the controller gets mapped to a url, and each method is accessed via that url. 7 # for example, this controller (if nothing is changed via url routing tables) is 8 # accessed at http://applicationurl/run_logger/action_method_name 9 # 10 # If an action method is called which doesn't have a method here, but does have a 11 # view template (as determined by filename), then the view is simply rendered. 12 # This is the case with run_logger/log_time. 13 14 def log_time_process 15 # the params hash holds the parameters sent with the request - it automagically maps 16 # parameters with names like 'runinfo[foo]' into a nested hash, which is cool. 17 18 # this pulls the runinfo nested hash out of the params hash, and then coerces each 19 # value to a Fixnum (via the #to_f method) 20 runinfo = params['runinfo'] 21 runinfo.each { |key, value| runinfo[key] = value.to_f } 22 23 # parses the date information into a Date object 24 date = params['date'] 25 date.each { |key, value| date[key] = value.to_f } 26 date = Date.new date['year'], date['month'], date['day'] 27 28 # since we can't prepopulate the session at initialization (it can't exist until 29 # there is a request to key the session off of), we have to initialize the session 30 # variable run_log if it's not set already. 31 # 32 # note: a ruby idiom is that this could also be said "session[:run_log] ||= []" 33 session[:run_log] = [] if session[:run_log].nil? 34 35 # now we _know_ we have an array in the session, go ahead and push the new entry 36 # object onto it. 37 session[:run_log] << RunLogEntry.new(runinfo['time'], runinfo['distance'], date) 38 39 # we're done processing the new entry, go ahead and redirect to the report_time 40 # action (right below us) 41 redirect_to :action => 'report_time' 42 end 43 44 def report_time 45 # same idea as above, we avoid a nil reference by taking either session[:run_log] or 46 # an empty array if that is nil 47 @run_log = session[:run_log] || [] 48 49 # default our average hash 50 @average = {'distance' => 0, 'time' => 0} 51 52 # if the array is empty, don't calculate averages. I added the #average method to the 53 # array class below - it's not very robust, but hey, it works for this application. 54 unless @run_log.length == 0 55 @average['distance'] = @run_log.collect { |e| e.distance }.average 56 @average['time'] = @run_log.collect { |e| e.time }.average 57 end 58 59 # if we don't do any sort of redirect or render, the controller automatically falls 60 # through to rendering the view template named the same as the action. In this case 61 # app/views/run_logger/report_time.rhtml 62 # 63 # Also, the reason we put the @run_log array and @average hash into instance variables 64 # is that rails makes those instance variables visible to the view as instance variables 65 # in the view template rhtml file. 66 end 67 68 def clear_log 69 # reset the run_log array in the session to an empty array 70 session[:run_log] = [] 71 72 # go back to our time reporting action 73 redirect_to :action => 'report_time' 74 end 75 end 76 77 # One of the coolest (and most dangerous if you're trying to break things) things in ruby 78 # is that you can open up classes and insert methods into them (or override them). Here, 79 # we add an #average method to the Array class, which then is available to _all_ arrays, 80 # including the ones we calculate for averages above. 81 class Array 82 def average 83 sum = 0 84 self.each { |v| sum += v } 85 sum / self.length 86 end 87 end