<?xml version="1.0" encoding="UTF-8"?>
<feed xml:lang="en-US" xmlns="http://www.w3.org/2005/Atom">
  <id>tag:www.integrallis.com,:/ourblogs/articles</id>
  <link type="text/html" href="http://www.integrallis.com" rel="alternate"/>
  <link type="application/atom+xml" href="http://www.integrallis.com/ourblogs/articles.atom" rel="self"/>
  <title>The Integrallis Blog : </title>
  <subtitle type="html">Using Java and Ruby to shape enterprise computing</subtitle>
  <updated>2008-06-23T16:52:04-04:00</updated>
  <generator uri="http://www.typosphere.org" version="4.x">Typo</generator>
  <entry>
    <id>tag:www.integrallis.com,:Article/22</id>
    <published>2007-12-26T12:59:47-05:00</published>
    <updated>2008-06-23T16:52:04-04:00</updated>
    <link type="text/html" href="http://www.integrallis.com/ourblogs/articles/2008/01/15/building-tempo-with-rails-part-vi" rel="alternate"/>
    <author>
      <name>Brian Sam-Bodden</name>
    </author>
    <title type="html">Building Tempo with Rails, Part VI</title>
    <category term="ruby" scheme="http://www.integrallis.com/ourblogs/articles/category/ruby" label="Ruby"/>
    <category term="rails" scheme="http://www.integrallis.com/ourblogs/articles/category/rails" label="Rails"/>
    <category term="Rails" scheme="http://www.integrallis.com/ourblogs/articles/tag/rails"/>
    <category term="Ruby" scheme="http://www.integrallis.com/ourblogs/articles/tag/ruby"/>
    <category term="agile" scheme="http://www.integrallis.com/ourblogs/articles/tag/agile"/>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p><img src="/ourblogs/files/rails.png" alt="Rails"/></p>

<p>In this installment we are going to build the Dashboard page of the Tempo application. The first incarnation of the Dashboard page will serve as the entry point/main page of the application and its main function will be to provide an interface for users to report time against a project-activity combination.</p>

<p>The user story that we are targeting is:</p>

<p>TMPO-29: “User enters Time” Business Critical [OPEN] 40 points 0% unassigned</p>

<p>The description above is from the Agile Project Management and Collaboration tool <a href="http://www.caimito.net/">Savila</a>. The “User enters Time” story is business critical, it is still OPEN, we have estimated 40 complexity points to it, is 0% completed and it has not been assigned to any team member (or no team member has volunteered for it!)</p>

<p>The description of the user story is "As a User I would like to enter time against a project and activity by providing a starting and ending time"</p>

<h1>User Interface</h1>

<p>Based on the story description I’ve come up with a rough sketch of what I picture the Dashboard page looking like after the first pass:</p>

<p><img src="/ourblogs/files/tempo_dashboard_sketch.png" alt="tempo dashboard sketch"/></p>

<p>The sketch above shows 3 different areas:</p>

<ul>
<li><em>Date Selection</em>: A Calendar-style component that will enable the user to select a given (active) date to enter time</li>
<li><em>Time Entry Details</em>: A form that will provide drop-downs for the Project, Activity, Start Time, End Time for the TimeEntry as well as a text area for a description. Optionally the user will be allowed to enter time as a number of hours to be reported against the given date (with no specific start or end times(1)).</li>
<li><em>Daily Summary</em>: A table displaying the time entries reported for the active date.</li>
</ul>

<p>(1) Notice that I’ve just created a new requirement that was not present in the original User Story. 
In our work to fulfill the main User Story we will set the stage to satisfy this new requirement but we should really create a new issue (story) to tackle that new piece of functionality (of course first we should check with the project owner and/or stakeholders)</p>

<h1>Dashboard Controller</h1>

<p>I started by creating the skeleton code and tests for the Dashboard Controller:</p>

<pre class="console">
/> script/generate rspec_controller dashboard   
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/dashboard
      exists  spec/controllers/
      exists  spec/helpers/
      create  spec/views/dashboard
      create  spec/controllers/dashboard_controller_spec.rb
      create  spec/helpers/dashboard_helper_spec.rb
      create  app/controllers/dashboard_controller.rb
      create  app/helpers/dashboard_helper.rb
</pre>

<p>Since we want the dashboard to be the default page for our application we can modify the config/routes.rb accordingly:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">map</span><span class="punct">.</span><span class="ident">connect</span> <span class="punct">'</span><span class="string"></span><span class="punct">',</span> <span class="symbol">:controller</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dashboard</span><span class="punct">&quot;,</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">index</span><span class="punct">&quot;</span></code></pre></div>

<p>With the skeleton in place I can now do a little planning about what I need to build.</p>

<h1>A bit of Design</h1>

<p>Here's what I know about the Dashboard page so far:</p>

<ol>
<li>The Dashboard page can only be shown if there is a user logged in. (done, taken care by the restful authentication plug-in)</li>
<li>When the user first navigates to the Dashboard page, the current date should be shown in the calendar date picker and on the “blog” style display on the time entry form</li>
<li>The Daily Work table should show all TimeEntries for the current user for the selected date</li>
<li>When the user selects a new date form the calendar date picker the "current date" (the date which under the times entered will be reported) should change.</li>
</ol>

<h1>Create the Views</h1>

<p>Let’s start by creating an index.rhtml template in the Views/dashboard directory. The index template will render three partials; one for a blog-style date, the TimeEntry form and one for the Daily Work table. The partials will be _current_date.rhtml, _form.rhtml and _time_entries.rhtml respectively.</p>

<h3>views/dashboard/index.rhtml</h3>

<p>The listing below shows the contents for index.rhtml. I used some of the CSS styles provided by ActiveScaffold to keep the look and feel consistent.</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">active-scaffold</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">create-view view</span><span class="punct">&quot;&gt;</span>  
    <span class="punct">&lt;%</span> <span class="ident">form_tag</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">create</span><span class="punct">'</span> <span class="keyword">do</span> <span class="punct">%&gt;</span><span class="string">
      &lt;h4</span><span class="punct">&gt;&lt;</span><span class="ident">div</span> <span class="ident">id</span><span class="punct">=&quot;</span><span class="string">current_date_div</span><span class="punct">&quot;&gt;&lt;%=</span><span class="string"> render :partial </span><span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">current_date</span><span class="punct">&quot;</span> <span class="punct">%&gt;</span><span class="string">&lt;/div</span><span class="punct">&gt;&lt;/</span><span class="regex">h4&gt;
      &lt;ol class=&quot;form&quot; &gt;
        &lt;%= render :partial =&gt; 'form' %&gt;
        &lt;p class=&quot;form-footer&quot;&gt;
          &lt;%= submit_tag &quot;Create&quot; %&gt;
        &lt;</span><span class="punct">/</span><span class="ident">p</span><span class="punct">&gt;</span>
      <span class="punct">&lt;/</span><span class="regex">ol&gt;
    &lt;% end %&gt;
  &lt;</span><span class="punct">/</span><span class="ident">div</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">div&gt;

&lt;br </span><span class="punct">/&gt;</span>
<span class="punct">&lt;</span><span class="ident">p</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="ident">div</span> <span class="ident">id</span><span class="punct">=&quot;</span><span class="string">time_entries_div</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;%=</span><span class="string"> render :partial </span><span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">time_entries</span><span class="punct">&quot;</span> <span class="punct">%&gt;</span><span class="string">
&lt;/div</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">p&gt;   </span></code></pre></div>

<p>The index.rhtml view renders a form (which body is contained in the _form.rhtml partial), the current date which is render by the partial _current_date.rhtml. Finally at the bottom we have a section that contains the daily work table summary which is rendered by the _time_entries.rhtml partial. Let's take a look at each one of those partials next:</p>

<h3>views/dashboard/_current_date.rhtml</h3>

<p>The idea here is to render a blog style data block as shown below:</p>

<p><img src="/ourblogs/files/tempo_dashboard_date_block.png" alt="tempo dashboard sketch"/></p>

<p>To render the blog style date I have a CSS snippet that I use to style a partial containing the current date. The partial _current_date.rhtml is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">dateblock</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">dateblock_month</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%=</span><span class="string"> &quot;<span class="expr">#{Time::RFC2822_MONTH_NAME[@current_date.month-1]}</span>&quot; %&gt;
  &lt;/div&gt;
  &lt;div class</span><span class="punct">=&quot;</span><span class="string">dateblock_day</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%=</span><span class="string"> &quot;<span class="expr">#{@current_date.day}</span>&quot; %&gt;
  &lt;/div&gt;
  &lt;div class</span><span class="punct">=&quot;</span><span class="string">dateblock_year</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%=</span><span class="string"> &quot;<span class="expr">#{@current_date.year}</span>&quot; %&gt;
  &lt;/div&gt;
&lt;/div&gt;</span></code></pre></div>

<p>Notice that I use an instance variable current_date that will be set in the index method of the dashboard controller if it cannot be retrieved from the session:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">index</span>
    <span class="keyword">unless</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> 
      <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">today</span>  
    <span class="keyword">end</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
  <span class="keyword">end</span></code></pre></div>

<p>In the controller the method to render the partial and update the instance and the session variable follows:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">current_date</span>
    <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">])</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="ident">render</span> <span class="symbol">:partial</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">current_date</span><span class="punct">'</span>
  <span class="keyword">end</span></code></pre></div>

<p>The CSS code for the dateblock is shown below (I've found it on a CSS site but I can't remember where):</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">/</span><span class="regex">*-------------------------------------------------
DATE BLOCK
-------------------------------------------------*</span><span class="punct">/</span>
<span class="punct">.</span><span class="ident">dateblock</span> <span class="punct">{</span>
  <span class="ident">text</span><span class="punct">-</span><span class="ident">align</span><span class="punct">:</span> <span class="ident">center</span><span class="punct">;</span>
  <span class="ident">width</span><span class="punct">:</span> <span class="number">50</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">family</span><span class="punct">:</span> <span class="ident">sans</span><span class="punct">-</span><span class="ident">serif</span><span class="punct">;</span>
  <span class="ident">border</span><span class="punct">:</span> <span class="ident">solid</span> <span class="number">1</span><span class="ident">px</span> <span class="ident">black</span><span class="punct">;</span>
  <span class="ident">padding</span><span class="punct">-</span><span class="ident">top</span><span class="punct">:</span> <span class="number">5</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">color</span><span class="punct">:</span> <span class="ident">white</span><span class="punct">;</span>
  <span class="ident">background</span><span class="punct">-</span><span class="ident">color</span><span class="symbol">:black</span><span class="punct">;</span>
  <span class="ident">margin</span><span class="punct">-</span><span class="ident">top</span><span class="punct">:</span> <span class="number">10</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">margin</span><span class="punct">-</span><span class="ident">bottom</span><span class="punct">:</span> <span class="number">10</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">line</span><span class="punct">-</span><span class="ident">height</span><span class="punct">:</span> <span class="number">1.22</span><span class="ident">em</span><span class="punct">;</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">family</span><span class="punct">:</span> <span class="ident">sans</span><span class="punct">-</span><span class="ident">serif</span><span class="punct">;</span>
<span class="punct">}</span>

<span class="punct">.</span><span class="ident">dateblock_month</span> <span class="punct">{</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">size</span><span class="punct">:</span> <span class="number">12</span><span class="ident">px</span><span class="punct">;</span>
<span class="punct">}</span>

<span class="punct">.</span><span class="ident">dateblock_day</span> <span class="punct">{</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">size</span><span class="punct">:</span> <span class="number">26</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">position</span><span class="punct">:</span> <span class="ident">relative</span><span class="punct">;</span>
  <span class="ident">top</span><span class="punct">:</span> <span class="punct">-</span><span class="number">2</span><span class="ident">px</span><span class="punct">;</span> 
<span class="punct">}</span>

<span class="punct">.</span><span class="ident">dateblock_year</span> <span class="punct">{</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">size</span><span class="punct">:</span> <span class="number">12</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">position</span><span class="punct">:</span> <span class="ident">relative</span><span class="punct">;</span>
  <span class="ident">top</span><span class="punct">:</span> <span class="punct">-</span><span class="number">2</span><span class="ident">px</span><span class="punct">;</span>
<span class="punct">}</span></code></pre></div>

<h3>views/_time_entries.rhtml</h3>

<p>For the Daily Work table showing all TimeEntries for the current user for the selected date we use the _time_entries.rhtml partial. This partial makes use of ActiveScaffold's ability to embed a scaffold in another controller, or view. To accomplish this we use the <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">render</span> <span class="symbol">:active<em>scaffold</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time</em>entries</span><span class="punct">'</span></code></pre></div> which will call the render_component passing a specific set of conditions (to be appended to the SQL select statement) and a custom label for the scaffold table:</p>

<div class="typocode"><pre><code class="typocode_ruby ">
<span class="punct">&lt;%=</span><span class="string"> render :active_scaffold </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entries</span><span class="punct">',</span> 
           <span class="symbol">:conditions</span> <span class="punct">=&gt;</span> 
             <span class="punct">[&quot;</span><span class="string">user_id = ? AND YEAR(start) = ? AND MONTH(start) = ? AND DAY(start) = ?</span><span class="punct">&quot;,</span>
              <span class="attribute">@current_user</span><span class="punct">.</span><span class="ident">id</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">],</span> 
           <span class="symbol">:label</span> <span class="punct">=&gt;</span> 
             <span class="punct">&quot;</span><span class="string">Time Entries for <span class="expr">#{Time::RFC2822_DAY_NAME[@current_date.wday]}</span>, <span class="expr">#{Time::RFC2822_MONTH_NAME[@current_date.month-1]}</span> <span class="expr">#{@current_date.day}</span> <span class="expr">#{@current_date.year}</span></span><span class="punct">&quot;</span> <span class="punct">%&gt;</span><span class="string"></span></code></pre></div>

<p>In the controller we need to modify the index method to also filter the collection of TimeEntry objects retrieved:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">index</span>
    <span class="keyword">unless</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> 
      <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">today</span>  
    <span class="keyword">end</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="attribute">@time_entries</span> <span class="punct">=</span> <span class="constant">TimeEntry</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:all</span><span class="punct">,</span> <span class="symbol">:conditions</span> <span class="punct">=&gt;</span> <span class="punct">[&quot;</span><span class="string">user_id = ? AND YEAR(start) = ? AND MONTH(start) = ? AND DAY(start) = ?</span><span class="punct">&quot;,</span> <span class="attribute">@current_user</span><span class="punct">.</span><span class="ident">id</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">])</span>
  <span class="keyword">end</span></code></pre></div>

<p>We also need a time_entries method to render the TimeEntry(s) based on the current_date in the session:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">time_entries</span>
    <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">])</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="ident">render</span> <span class="symbol">:partial</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entries</span><span class="punct">'</span>
  <span class="keyword">end</span></code></pre></div>

<p>The daily work table should now display all the TimeEntry(s) for the current/selected date:</p>

<p><img src="/ourblogs/files/tempo_dashboard_closeup.png" alt="tempo dashboard sketch"/></p>

<h3>views/_form.rhtml</h3>

<p>The form partial is fairly simple and provides elements to select the project, the activity, time picker for the start and end dates, an optional total hours worked field and a text area to enter comments associated with the work being reported.</p>

<p>The complete source for the partial is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;%=</span><span class="string"> error_messages_for 'time_entry' %&gt;

&lt;!--[form:time_entry]--&gt;
&lt;li class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_project</span><span class="punct">&quot;&gt;</span><span class="constant">Project</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> collection_select 'time_entry', 'project', current_user.projects, 'id', 'name' %&gt;&lt;/dd&gt;
    &lt;%</span><span class="punct">=</span> <span class="ident">observe_field</span> <span class="punct">'</span><span class="string">time_entry_project</span><span class="punct">',</span> <span class="symbol">:update</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry_activity</span><span class="punct">',</span> <span class="symbol">:with</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">project_id</span><span class="punct">&quot;,</span> <span class="symbol">:url</span> <span class="punct">=&gt;</span> <span class="punct">{</span> <span class="symbol">:controller</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dashboard</span><span class="punct">&quot;,</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">load_activities</span><span class="punct">&quot;</span> <span class="punct">}</span> <span class="punct">%&gt;</span><span class="string">
  &lt;/dl</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">li&gt;

&lt;li class=&quot;form-element&quot;&gt;
  &lt;dl&gt;
    &lt;dt&gt;&lt;label for=&quot;time_entry_projects_activity&quot;&gt;Activity&lt;</span><span class="punct">/</span><span class="ident">label</span><span class="punct">&gt;&lt;/</span><span class="regex">dt&gt;
    &lt;dd&gt;&lt;%= select 'time_entry', 'projects_activity', ['--select a project--'] %&gt;&lt;</span><span class="punct">/</span><span class="ident">dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_start</span><span class="punct">&quot;&gt;</span><span class="constant">Start</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">start</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_end</span><span class="punct">&quot;&gt;</span><span class="constant">End</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">end</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_hours</span><span class="punct">&quot;&gt;</span><span class="constant">Hours</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> text_field 'time_entry', 'hours'  %&gt;&lt;/dd&gt;
  &lt;/dl&gt;
&lt;/li&gt;

&lt;li class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_comment</span><span class="punct">&quot;&gt;</span><span class="constant">Long</span> <span class="constant">Description</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> text_area 'time_entry', 'comment', 'rows' </span><span class="punct">=&gt;</span> <span class="number">12</span><span class="punct">,</span> <span class="punct">'</span><span class="string">cols</span><span class="punct">'</span> <span class="punct">=&gt;</span> <span class="number">45</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>
<span class="punct">&lt;!--[</span><span class="ident">eoform</span><span class="symbol">:time_entry</span><span class="punct">]--&gt;</span></code></pre></div>

<h4>A little Ajax</h4>

<p>Let's dissect the form contents. First at the very top we have a form element that displays a drop-down for the projects that the current user is part of. Since we have specific activities per project we need to use some Ajax magic to populate the project activities drop-down. </p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_project</span><span class="punct">&quot;&gt;</span><span class="constant">Project</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> collection_select 'time_entry', 'project', current_user.projects, 'id', 'name' %&gt;&lt;/dd&gt;
    &lt;%</span><span class="punct">=</span> <span class="ident">observe_field</span> <span class="punct">'</span><span class="string">time_entry_project</span><span class="punct">',</span> <span class="symbol">:update</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry_activity</span><span class="punct">',</span> <span class="symbol">:with</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">project_id</span><span class="punct">&quot;,</span> <span class="symbol">:url</span> <span class="punct">=&gt;</span> <span class="punct">{</span> <span class="symbol">:controller</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dashboard</span><span class="punct">&quot;,</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">load_activities</span><span class="punct">&quot;</span> <span class="punct">}</span> <span class="punct">%&gt;</span><span class="string">
  &lt;/dl</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">li&gt;

&lt;li class=&quot;form-element&quot;&gt;
  &lt;dl&gt;
    &lt;dt&gt;&lt;label for=&quot;time_entry_projects_activity&quot;&gt;Activity&lt;</span><span class="punct">/</span><span class="ident">label</span><span class="punct">&gt;&lt;/</span><span class="regex">dt&gt;
    &lt;dd&gt;&lt;%= select 'time_entry', 'projects_activity', ['--select a project--'] %&gt;&lt;</span><span class="punct">/</span><span class="ident">dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span></code></pre></div>

<p>To accomplish this I use the observe_field tag, Rails lets you listen to events on a field such as the value of a field to which you can respond by making an Ajax call to an action handler with the current value of the field being observed sent to the action handler in the post data of the call. In the case above we are updating the drop-down time_entry by invoking the action load_activities in the controller, which is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">load_activities</span>
    <span class="ident">project</span> <span class="punct">=</span> <span class="constant">Project</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:project_id</span><span class="punct">])</span>
    <span class="attribute">@projects_activities</span> <span class="punct">=</span> <span class="ident">project</span><span class="punct">.</span><span class="ident">projects_activity</span>
  <span class="keyword">end</span></code></pre></div>

<h4>Time Picking</h4>

<p>To enable time picking on the form fields for start and end times I used Thong Kuah TimePicker plug-in which can be found at http://rubyforge.org/projects/timepicker/. As described in the read me file, this plug-in follow the usage of ActionView::Helpers::DateHelper closely.</p>

<p>Below is a preview of what the time picking drop-downs will look like:</p>

<p><img src="/ourblogs/files/tempo_dashboard_time_pick.png" alt="tempo dashboard sketch"/></p>

<p>To install the plug-in I again use Piston:</p>

<pre class="console">
/> piston import svn://rubyforge.org/var/svn/timepicker/trunk vendor/plugins/timepicker
Exported r4 from 'svn://rubyforge.org/var/svn/timepicker/trunk vendor/plugins/timepicker' to 'vendor/plugins/timepicker'
</pre>

<p>With the plug-in installed you can now use time_picker(datetime, options = {}) in your views.</p>

<p>In our case the usage is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_start</span><span class="punct">&quot;&gt;</span><span class="constant">Start</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">start</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_end</span><span class="punct">&quot;&gt;</span><span class="constant">End</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">end</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span></code></pre></div>

<h3>Calendar Picker</h3>

<p>For the current date selection I'm using a set of plug-ins that work well with ActiveScaffold. Calendar Date Select can be found at http://code.google.com/p/calendardateselect/. There is also a bridge to integrate it into ActiveScaffold at http://wiki.activescaffold.com/wiki/published/CalendarDateSelectBridge:</p>

<pre class="console">
/> piston import http://calendardateselect.googlecode.com/svn/tags/calendar_date_select vendor/plugins/calendar_date_select
Exported r154 from 'http://calendardateselect.googlecode.com/svn/tags/calendar_date_select' to 'vendor/plugins/calendar_date_select'
/> piston import http://activescaffold.googlecode.com/svn/bridges/active_scaffold_calendar_date_select_bridge vendor/plugins/active_scaffold_calendar_date_select_bridge
Exported r634 from 'http://activescaffold.googlecode.com/svn/bridges/active_scaffold_calendar_date_select_bridge' to 'vendor/plugins/active_scaffold_calendar_date_select_bridge'
/> 
</pre>

<p>Once installed, I placed the code for the date picker in the main application layout (application.rhtml). The snippet below shows only when the controller is the dashboard controller and the action is the index action:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;!--</span> <span class="punct">============</span> <span class="punct">--&gt;</span> 
<span class="punct">&lt;!--</span> <span class="constant">Right</span> <span class="constant">Column</span> <span class="punct">--&gt;</span>
<span class="punct">&lt;!--</span> <span class="punct">============</span> <span class="punct">--&gt;</span> 
<span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">Right</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">col</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%</span> <span class="keyword">if</span> <span class="ident">current_page?</span><span class="punct">({'</span><span class="string">controller</span><span class="punct">'</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">dashboard</span><span class="punct">',</span> <span class="punct">'</span><span class="string">action</span><span class="punct">'</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">index</span><span class="punct">'})</span> <span class="punct">-%&gt;</span><span class="string">
      &lt;h1</span><span class="punct">&gt;</span><span class="constant">Select</span> <span class="ident">a</span> <span class="constant">Date</span><span class="punct">&lt;/</span><span class="regex">h1&gt;
      &lt;%= calendar_date_select_tag 
          :current_date, 
          @current_date, 
          {:embedded =&gt; &quot;true&quot;,
           :onchange =&gt; &quot;new Ajax.Updater('current_date_div', '</span><span class="punct">/</span><span class="ident">dashboard</span><span class="punct">/</span><span class="ident">current_date?current_date</span><span class="punct">='</span><span class="string"> + $H({current_date: this.value}).toQueryString(), 
                        {asynchronous:true, evalScripts:true}); 
                        new Ajax.Updater(</span><span class="punct">'</span><span class="ident">time_entries_div</span><span class="punct">'</span><span class="string">, </span><span class="punct">'/</span><span class="ident">dashboard</span><span class="punct">/</span><span class="ident">time_entries?current_date</span><span class="punct">='</span><span class="string"> + $H({current_date: this.value}).toQueryString(),
                        {asynchronous:true, evalScripts:true})&quot;} 
      %&gt;
    &lt;% else -%&gt;
      &lt;h1&gt;[[Help Title]]&lt;/h1&gt;
      &lt;p&gt;[[Help Body]]&lt;/p&gt;
    &lt;% end -%&gt;
  &lt;/div&gt;
&lt;/div&gt; </span></code></pre></div>

<p>Finally we need a create method in the controller to handle the creation of the new time entry when we submit the form:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">create</span>
    <span class="ident">project</span> <span class="punct">=</span> <span class="constant">Project</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:project</span><span class="punct">])</span>
    <span class="ident">projects_activity</span> <span class="punct">=</span> <span class="constant">ProjectsActivity</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:projects_activity</span><span class="punct">])</span>
    <span class="attribute">@time_entry</span> <span class="punct">=</span> <span class="constant">TimeEntry</span><span class="punct">.</span><span class="ident">new</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">user</span> <span class="punct">=</span> <span class="ident">current_user</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">project</span> <span class="punct">=</span> <span class="ident">project</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">projects_activity</span> <span class="punct">=</span> <span class="ident">projects_activity</span>
    <span class="ident">start_time</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:start</span><span class="punct">])</span>
    <span class="ident">end_time</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:end</span><span class="punct">])</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">hours</span> <span class="punct">=</span> <span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:hours</span><span class="punct">]</span>

    <span class="keyword">unless</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> 
      <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">today</span>
    <span class="keyword">end</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">start</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">utc</span><span class="punct">(</span><span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">,</span> <span class="ident">start_time</span><span class="punct">.</span><span class="ident">hour</span><span class="punct">,</span> <span class="ident">start_time</span><span class="punct">.</span><span class="ident">min</span><span class="punct">)</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">utc</span><span class="punct">(</span><span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">,</span> <span class="ident">end_time</span><span class="punct">.</span><span class="ident">hour</span><span class="punct">,</span> <span class="ident">end_time</span><span class="punct">.</span><span class="ident">min</span><span class="punct">)</span>

    <span class="keyword">if</span> <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">save</span>
      <span class="ident">flash</span><span class="punct">[</span><span class="symbol">:notice</span><span class="punct">]</span> <span class="punct">=</span> <span class="punct">'</span><span class="string">TimeEntry was successfully created.</span><span class="punct">'</span>
      <span class="ident">redirect_to</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">index</span><span class="punct">'</span>
    <span class="keyword">else</span>
      <span class="ident">render</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">index</span><span class="punct">'</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span></code></pre></div>

<p>In the code above we first find the project and the project activity based on the parameters posted with the form, next we create a new TimeEntry object and set the values on the form. The start and end times on the time entry are calculated using the current_date value and the hour and minutes selected on the time pickers.</p>

<p><img src="/ourblogs/files/tempo_dashboard_sm_01.png" alt="tempo dashboard"/></p>

<p>In the next installment we will move beyond the simple capabilities implemented so far and begin thinking about what it takes to polish a product so that it can be ready for mass consumption. Until the next time.</p>      </div>
    </summary>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p><img src="/ourblogs/files/rails.png" alt="Rails"/></p>

<p>In this installment we are going to build the Dashboard page of the Tempo application. The first incarnation of the Dashboard page will serve as the entry point/main page of the application and its main function will be to provide an interface for users to report time against a project-activity combination.</p>

<p>The user story that we are targeting is:</p>

<p>TMPO-29: “User enters Time” Business Critical [OPEN] 40 points 0% unassigned</p>

<p>The description above is from the Agile Project Management and Collaboration tool <a href="http://www.caimito.net/">Savila</a>. The “User enters Time” story is business critical, it is still OPEN, we have estimated 40 complexity points to it, is 0% completed and it has not been assigned to any team member (or no team member has volunteered for it!)</p>

<p>The description of the user story is "As a User I would like to enter time against a project and activity by providing a starting and ending time"</p>

<h1>User Interface</h1>

<p>Based on the story description I’ve come up with a rough sketch of what I picture the Dashboard page looking like after the first pass:</p>

<p><img src="/ourblogs/files/tempo_dashboard_sketch.png" alt="tempo dashboard sketch"/></p>

<p>The sketch above shows 3 different areas:</p>

<ul>
<li><em>Date Selection</em>: A Calendar-style component that will enable the user to select a given (active) date to enter time</li>
<li><em>Time Entry Details</em>: A form that will provide drop-downs for the Project, Activity, Start Time, End Time for the TimeEntry as well as a text area for a description. Optionally the user will be allowed to enter time as a number of hours to be reported against the given date (with no specific start or end times(1)).</li>
<li><em>Daily Summary</em>: A table displaying the time entries reported for the active date.</li>
</ul>

<p>(1) Notice that I’ve just created a new requirement that was not present in the original User Story. 
In our work to fulfill the main User Story we will set the stage to satisfy this new requirement but we should really create a new issue (story) to tackle that new piece of functionality (of course first we should check with the project owner and/or stakeholders)</p>

<h1>Dashboard Controller</h1>

<p>I started by creating the skeleton code and tests for the Dashboard Controller:</p>

<pre class="console">
/> script/generate rspec_controller dashboard   
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/dashboard
      exists  spec/controllers/
      exists  spec/helpers/
      create  spec/views/dashboard
      create  spec/controllers/dashboard_controller_spec.rb
      create  spec/helpers/dashboard_helper_spec.rb
      create  app/controllers/dashboard_controller.rb
      create  app/helpers/dashboard_helper.rb
</pre>

<p>Since we want the dashboard to be the default page for our application we can modify the config/routes.rb accordingly:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">map</span><span class="punct">.</span><span class="ident">connect</span> <span class="punct">'</span><span class="string"></span><span class="punct">',</span> <span class="symbol">:controller</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dashboard</span><span class="punct">&quot;,</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">index</span><span class="punct">&quot;</span></code></pre></div>

<p>With the skeleton in place I can now do a little planning about what I need to build.</p>

<h1>A bit of Design</h1>

<p>Here's what I know about the Dashboard page so far:</p>

<ol>
<li>The Dashboard page can only be shown if there is a user logged in. (done, taken care by the restful authentication plug-in)</li>
<li>When the user first navigates to the Dashboard page, the current date should be shown in the calendar date picker and on the “blog” style display on the time entry form</li>
<li>The Daily Work table should show all TimeEntries for the current user for the selected date</li>
<li>When the user selects a new date form the calendar date picker the "current date" (the date which under the times entered will be reported) should change.</li>
</ol>

<h1>Create the Views</h1>

<p>Let’s start by creating an index.rhtml template in the Views/dashboard directory. The index template will render three partials; one for a blog-style date, the TimeEntry form and one for the Daily Work table. The partials will be _current_date.rhtml, _form.rhtml and _time_entries.rhtml respectively.</p>

<h3>views/dashboard/index.rhtml</h3>

<p>The listing below shows the contents for index.rhtml. I used some of the CSS styles provided by ActiveScaffold to keep the look and feel consistent.</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">active-scaffold</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">create-view view</span><span class="punct">&quot;&gt;</span>  
    <span class="punct">&lt;%</span> <span class="ident">form_tag</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">create</span><span class="punct">'</span> <span class="keyword">do</span> <span class="punct">%&gt;</span><span class="string">
      &lt;h4</span><span class="punct">&gt;&lt;</span><span class="ident">div</span> <span class="ident">id</span><span class="punct">=&quot;</span><span class="string">current_date_div</span><span class="punct">&quot;&gt;&lt;%=</span><span class="string"> render :partial </span><span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">current_date</span><span class="punct">&quot;</span> <span class="punct">%&gt;</span><span class="string">&lt;/div</span><span class="punct">&gt;&lt;/</span><span class="regex">h4&gt;
      &lt;ol class=&quot;form&quot; &gt;
        &lt;%= render :partial =&gt; 'form' %&gt;
        &lt;p class=&quot;form-footer&quot;&gt;
          &lt;%= submit_tag &quot;Create&quot; %&gt;
        &lt;</span><span class="punct">/</span><span class="ident">p</span><span class="punct">&gt;</span>
      <span class="punct">&lt;/</span><span class="regex">ol&gt;
    &lt;% end %&gt;
  &lt;</span><span class="punct">/</span><span class="ident">div</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">div&gt;

&lt;br </span><span class="punct">/&gt;</span>
<span class="punct">&lt;</span><span class="ident">p</span><span class="punct">&gt;</span>
<span class="punct">&lt;</span><span class="ident">div</span> <span class="ident">id</span><span class="punct">=&quot;</span><span class="string">time_entries_div</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;%=</span><span class="string"> render :partial </span><span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">time_entries</span><span class="punct">&quot;</span> <span class="punct">%&gt;</span><span class="string">
&lt;/div</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">p&gt;   </span></code></pre></div>

<p>The index.rhtml view renders a form (which body is contained in the _form.rhtml partial), the current date which is render by the partial _current_date.rhtml. Finally at the bottom we have a section that contains the daily work table summary which is rendered by the _time_entries.rhtml partial. Let's take a look at each one of those partials next:</p>

<h3>views/dashboard/_current_date.rhtml</h3>

<p>The idea here is to render a blog style data block as shown below:</p>

<p><img src="/ourblogs/files/tempo_dashboard_date_block.png" alt="tempo dashboard sketch"/></p>

<p>To render the blog style date I have a CSS snippet that I use to style a partial containing the current date. The partial _current_date.rhtml is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">dateblock</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">dateblock_month</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%=</span><span class="string"> &quot;<span class="expr">#{Time::RFC2822_MONTH_NAME[@current_date.month-1]}</span>&quot; %&gt;
  &lt;/div&gt;
  &lt;div class</span><span class="punct">=&quot;</span><span class="string">dateblock_day</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%=</span><span class="string"> &quot;<span class="expr">#{@current_date.day}</span>&quot; %&gt;
  &lt;/div&gt;
  &lt;div class</span><span class="punct">=&quot;</span><span class="string">dateblock_year</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%=</span><span class="string"> &quot;<span class="expr">#{@current_date.year}</span>&quot; %&gt;
  &lt;/div&gt;
&lt;/div&gt;</span></code></pre></div>

<p>Notice that I use an instance variable current_date that will be set in the index method of the dashboard controller if it cannot be retrieved from the session:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">index</span>
    <span class="keyword">unless</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> 
      <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">today</span>  
    <span class="keyword">end</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
  <span class="keyword">end</span></code></pre></div>

<p>In the controller the method to render the partial and update the instance and the session variable follows:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">current_date</span>
    <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">])</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="ident">render</span> <span class="symbol">:partial</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">current_date</span><span class="punct">'</span>
  <span class="keyword">end</span></code></pre></div>

<p>The CSS code for the dateblock is shown below (I've found it on a CSS site but I can't remember where):</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">/</span><span class="regex">*-------------------------------------------------
DATE BLOCK
-------------------------------------------------*</span><span class="punct">/</span>
<span class="punct">.</span><span class="ident">dateblock</span> <span class="punct">{</span>
  <span class="ident">text</span><span class="punct">-</span><span class="ident">align</span><span class="punct">:</span> <span class="ident">center</span><span class="punct">;</span>
  <span class="ident">width</span><span class="punct">:</span> <span class="number">50</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">family</span><span class="punct">:</span> <span class="ident">sans</span><span class="punct">-</span><span class="ident">serif</span><span class="punct">;</span>
  <span class="ident">border</span><span class="punct">:</span> <span class="ident">solid</span> <span class="number">1</span><span class="ident">px</span> <span class="ident">black</span><span class="punct">;</span>
  <span class="ident">padding</span><span class="punct">-</span><span class="ident">top</span><span class="punct">:</span> <span class="number">5</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">color</span><span class="punct">:</span> <span class="ident">white</span><span class="punct">;</span>
  <span class="ident">background</span><span class="punct">-</span><span class="ident">color</span><span class="symbol">:black</span><span class="punct">;</span>
  <span class="ident">margin</span><span class="punct">-</span><span class="ident">top</span><span class="punct">:</span> <span class="number">10</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">margin</span><span class="punct">-</span><span class="ident">bottom</span><span class="punct">:</span> <span class="number">10</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">line</span><span class="punct">-</span><span class="ident">height</span><span class="punct">:</span> <span class="number">1.22</span><span class="ident">em</span><span class="punct">;</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">family</span><span class="punct">:</span> <span class="ident">sans</span><span class="punct">-</span><span class="ident">serif</span><span class="punct">;</span>
<span class="punct">}</span>

<span class="punct">.</span><span class="ident">dateblock_month</span> <span class="punct">{</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">size</span><span class="punct">:</span> <span class="number">12</span><span class="ident">px</span><span class="punct">;</span>
<span class="punct">}</span>

<span class="punct">.</span><span class="ident">dateblock_day</span> <span class="punct">{</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">size</span><span class="punct">:</span> <span class="number">26</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">position</span><span class="punct">:</span> <span class="ident">relative</span><span class="punct">;</span>
  <span class="ident">top</span><span class="punct">:</span> <span class="punct">-</span><span class="number">2</span><span class="ident">px</span><span class="punct">;</span> 
<span class="punct">}</span>

<span class="punct">.</span><span class="ident">dateblock_year</span> <span class="punct">{</span>
  <span class="ident">font</span><span class="punct">-</span><span class="ident">size</span><span class="punct">:</span> <span class="number">12</span><span class="ident">px</span><span class="punct">;</span>
  <span class="ident">position</span><span class="punct">:</span> <span class="ident">relative</span><span class="punct">;</span>
  <span class="ident">top</span><span class="punct">:</span> <span class="punct">-</span><span class="number">2</span><span class="ident">px</span><span class="punct">;</span>
<span class="punct">}</span></code></pre></div>

<h3>views/_time_entries.rhtml</h3>

<p>For the Daily Work table showing all TimeEntries for the current user for the selected date we use the _time_entries.rhtml partial. This partial makes use of ActiveScaffold's ability to embed a scaffold in another controller, or view. To accomplish this we use the <div class="typocode"><pre><code class="typocode_ruby "><span class="ident">render</span> <span class="symbol">:active<em>scaffold</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time</em>entries</span><span class="punct">'</span></code></pre></div> which will call the render_component passing a specific set of conditions (to be appended to the SQL select statement) and a custom label for the scaffold table:</p>

<div class="typocode"><pre><code class="typocode_ruby ">
<span class="punct">&lt;%=</span><span class="string"> render :active_scaffold </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entries</span><span class="punct">',</span> 
           <span class="symbol">:conditions</span> <span class="punct">=&gt;</span> 
             <span class="punct">[&quot;</span><span class="string">user_id = ? AND YEAR(start) = ? AND MONTH(start) = ? AND DAY(start) = ?</span><span class="punct">&quot;,</span>
              <span class="attribute">@current_user</span><span class="punct">.</span><span class="ident">id</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">],</span> 
           <span class="symbol">:label</span> <span class="punct">=&gt;</span> 
             <span class="punct">&quot;</span><span class="string">Time Entries for <span class="expr">#{Time::RFC2822_DAY_NAME[@current_date.wday]}</span>, <span class="expr">#{Time::RFC2822_MONTH_NAME[@current_date.month-1]}</span> <span class="expr">#{@current_date.day}</span> <span class="expr">#{@current_date.year}</span></span><span class="punct">&quot;</span> <span class="punct">%&gt;</span><span class="string"></span></code></pre></div>

<p>In the controller we need to modify the index method to also filter the collection of TimeEntry objects retrieved:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">index</span>
    <span class="keyword">unless</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> 
      <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">today</span>  
    <span class="keyword">end</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="attribute">@time_entries</span> <span class="punct">=</span> <span class="constant">TimeEntry</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="symbol">:all</span><span class="punct">,</span> <span class="symbol">:conditions</span> <span class="punct">=&gt;</span> <span class="punct">[&quot;</span><span class="string">user_id = ? AND YEAR(start) = ? AND MONTH(start) = ? AND DAY(start) = ?</span><span class="punct">&quot;,</span> <span class="attribute">@current_user</span><span class="punct">.</span><span class="ident">id</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">])</span>
  <span class="keyword">end</span></code></pre></div>

<p>We also need a time_entries method to render the TimeEntry(s) based on the current_date in the session:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">time_entries</span>
    <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">])</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="ident">render</span> <span class="symbol">:partial</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entries</span><span class="punct">'</span>
  <span class="keyword">end</span></code></pre></div>

<p>The daily work table should now display all the TimeEntry(s) for the current/selected date:</p>

<p><img src="/ourblogs/files/tempo_dashboard_closeup.png" alt="tempo dashboard sketch"/></p>

<h3>views/_form.rhtml</h3>

<p>The form partial is fairly simple and provides elements to select the project, the activity, time picker for the start and end dates, an optional total hours worked field and a text area to enter comments associated with the work being reported.</p>

<p>The complete source for the partial is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;%=</span><span class="string"> error_messages_for 'time_entry' %&gt;

&lt;!--[form:time_entry]--&gt;
&lt;li class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_project</span><span class="punct">&quot;&gt;</span><span class="constant">Project</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> collection_select 'time_entry', 'project', current_user.projects, 'id', 'name' %&gt;&lt;/dd&gt;
    &lt;%</span><span class="punct">=</span> <span class="ident">observe_field</span> <span class="punct">'</span><span class="string">time_entry_project</span><span class="punct">',</span> <span class="symbol">:update</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry_activity</span><span class="punct">',</span> <span class="symbol">:with</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">project_id</span><span class="punct">&quot;,</span> <span class="symbol">:url</span> <span class="punct">=&gt;</span> <span class="punct">{</span> <span class="symbol">:controller</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dashboard</span><span class="punct">&quot;,</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">load_activities</span><span class="punct">&quot;</span> <span class="punct">}</span> <span class="punct">%&gt;</span><span class="string">
  &lt;/dl</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">li&gt;

&lt;li class=&quot;form-element&quot;&gt;
  &lt;dl&gt;
    &lt;dt&gt;&lt;label for=&quot;time_entry_projects_activity&quot;&gt;Activity&lt;</span><span class="punct">/</span><span class="ident">label</span><span class="punct">&gt;&lt;/</span><span class="regex">dt&gt;
    &lt;dd&gt;&lt;%= select 'time_entry', 'projects_activity', ['--select a project--'] %&gt;&lt;</span><span class="punct">/</span><span class="ident">dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_start</span><span class="punct">&quot;&gt;</span><span class="constant">Start</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">start</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_end</span><span class="punct">&quot;&gt;</span><span class="constant">End</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">end</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_hours</span><span class="punct">&quot;&gt;</span><span class="constant">Hours</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> text_field 'time_entry', 'hours'  %&gt;&lt;/dd&gt;
  &lt;/dl&gt;
&lt;/li&gt;

&lt;li class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_comment</span><span class="punct">&quot;&gt;</span><span class="constant">Long</span> <span class="constant">Description</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> text_area 'time_entry', 'comment', 'rows' </span><span class="punct">=&gt;</span> <span class="number">12</span><span class="punct">,</span> <span class="punct">'</span><span class="string">cols</span><span class="punct">'</span> <span class="punct">=&gt;</span> <span class="number">45</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>
<span class="punct">&lt;!--[</span><span class="ident">eoform</span><span class="symbol">:time_entry</span><span class="punct">]--&gt;</span></code></pre></div>

<h4>A little Ajax</h4>

<p>Let's dissect the form contents. First at the very top we have a form element that displays a drop-down for the projects that the current user is part of. Since we have specific activities per project we need to use some Ajax magic to populate the project activities drop-down. </p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_project</span><span class="punct">&quot;&gt;</span><span class="constant">Project</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> collection_select 'time_entry', 'project', current_user.projects, 'id', 'name' %&gt;&lt;/dd&gt;
    &lt;%</span><span class="punct">=</span> <span class="ident">observe_field</span> <span class="punct">'</span><span class="string">time_entry_project</span><span class="punct">',</span> <span class="symbol">:update</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry_activity</span><span class="punct">',</span> <span class="symbol">:with</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">project_id</span><span class="punct">&quot;,</span> <span class="symbol">:url</span> <span class="punct">=&gt;</span> <span class="punct">{</span> <span class="symbol">:controller</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dashboard</span><span class="punct">&quot;,</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">load_activities</span><span class="punct">&quot;</span> <span class="punct">}</span> <span class="punct">%&gt;</span><span class="string">
  &lt;/dl</span><span class="punct">&gt;</span>
<span class="punct">&lt;/</span><span class="regex">li&gt;

&lt;li class=&quot;form-element&quot;&gt;
  &lt;dl&gt;
    &lt;dt&gt;&lt;label for=&quot;time_entry_projects_activity&quot;&gt;Activity&lt;</span><span class="punct">/</span><span class="ident">label</span><span class="punct">&gt;&lt;/</span><span class="regex">dt&gt;
    &lt;dd&gt;&lt;%= select 'time_entry', 'projects_activity', ['--select a project--'] %&gt;&lt;</span><span class="punct">/</span><span class="ident">dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span></code></pre></div>

<p>To accomplish this I use the observe_field tag, Rails lets you listen to events on a field such as the value of a field to which you can respond by making an Ajax call to an action handler with the current value of the field being observed sent to the action handler in the post data of the call. In the case above we are updating the drop-down time_entry by invoking the action load_activities in the controller, which is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">load_activities</span>
    <span class="ident">project</span> <span class="punct">=</span> <span class="constant">Project</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:project_id</span><span class="punct">])</span>
    <span class="attribute">@projects_activities</span> <span class="punct">=</span> <span class="ident">project</span><span class="punct">.</span><span class="ident">projects_activity</span>
  <span class="keyword">end</span></code></pre></div>

<h4>Time Picking</h4>

<p>To enable time picking on the form fields for start and end times I used Thong Kuah TimePicker plug-in which can be found at http://rubyforge.org/projects/timepicker/. As described in the read me file, this plug-in follow the usage of ActionView::Helpers::DateHelper closely.</p>

<p>Below is a preview of what the time picking drop-downs will look like:</p>

<p><img src="/ourblogs/files/tempo_dashboard_time_pick.png" alt="tempo dashboard sketch"/></p>

<p>To install the plug-in I again use Piston:</p>

<pre class="console">
/> piston import svn://rubyforge.org/var/svn/timepicker/trunk vendor/plugins/timepicker
Exported r4 from 'svn://rubyforge.org/var/svn/timepicker/trunk vendor/plugins/timepicker' to 'vendor/plugins/timepicker'
</pre>

<p>With the plug-in installed you can now use time_picker(datetime, options = {}) in your views.</p>

<p>In our case the usage is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_start</span><span class="punct">&quot;&gt;</span><span class="constant">Start</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">start</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span>

<span class="punct">&lt;</span><span class="ident">li</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">form-element</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">dl</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dt</span><span class="punct">&gt;&lt;</span><span class="ident">label</span> <span class="keyword">for</span><span class="punct">=&quot;</span><span class="string">time_entry_end</span><span class="punct">&quot;&gt;</span><span class="constant">End</span><span class="punct">&lt;/</span><span class="regex">label&gt;&lt;</span><span class="punct">/</span><span class="ident">dt</span><span class="punct">&gt;</span>
    <span class="punct">&lt;</span><span class="ident">dd</span><span class="punct">&gt;&lt;%=</span><span class="string"> time_picker Time.now, {:time_format </span><span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">12</span><span class="punct">',</span> <span class="symbol">:minute_step</span> <span class="punct">=&gt;</span> <span class="number">30</span><span class="punct">,</span> <span class="symbol">:prefix</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">time_entry</span><span class="punct">',</span> <span class="symbol">:field_name</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">end</span><span class="punct">',</span> <span class="symbol">:time_separator</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">:</span><span class="punct">'}</span> <span class="punct">%&gt;</span><span class="string">&lt;/dd</span><span class="punct">&gt;</span>
  <span class="punct">&lt;/</span><span class="regex">dl&gt;
&lt;</span><span class="punct">/</span><span class="ident">li</span><span class="punct">&gt;</span></code></pre></div>

<h3>Calendar Picker</h3>

<p>For the current date selection I'm using a set of plug-ins that work well with ActiveScaffold. Calendar Date Select can be found at http://code.google.com/p/calendardateselect/. There is also a bridge to integrate it into ActiveScaffold at http://wiki.activescaffold.com/wiki/published/CalendarDateSelectBridge:</p>

<pre class="console">
/> piston import http://calendardateselect.googlecode.com/svn/tags/calendar_date_select vendor/plugins/calendar_date_select
Exported r154 from 'http://calendardateselect.googlecode.com/svn/tags/calendar_date_select' to 'vendor/plugins/calendar_date_select'
/> piston import http://activescaffold.googlecode.com/svn/bridges/active_scaffold_calendar_date_select_bridge vendor/plugins/active_scaffold_calendar_date_select_bridge
Exported r634 from 'http://activescaffold.googlecode.com/svn/bridges/active_scaffold_calendar_date_select_bridge' to 'vendor/plugins/active_scaffold_calendar_date_select_bridge'
/> 
</pre>

<p>Once installed, I placed the code for the date picker in the main application layout (application.rhtml). The snippet below shows only when the controller is the dashboard controller and the action is the index action:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="punct">&lt;!--</span> <span class="punct">============</span> <span class="punct">--&gt;</span> 
<span class="punct">&lt;!--</span> <span class="constant">Right</span> <span class="constant">Column</span> <span class="punct">--&gt;</span>
<span class="punct">&lt;!--</span> <span class="punct">============</span> <span class="punct">--&gt;</span> 
<span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">Right</span><span class="punct">&quot;&gt;</span>
  <span class="punct">&lt;</span><span class="ident">div</span> <span class="keyword">class</span><span class="punct">=&quot;</span><span class="string">col</span><span class="punct">&quot;&gt;</span>
    <span class="punct">&lt;%</span> <span class="keyword">if</span> <span class="ident">current_page?</span><span class="punct">({'</span><span class="string">controller</span><span class="punct">'</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">dashboard</span><span class="punct">',</span> <span class="punct">'</span><span class="string">action</span><span class="punct">'</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">index</span><span class="punct">'})</span> <span class="punct">-%&gt;</span><span class="string">
      &lt;h1</span><span class="punct">&gt;</span><span class="constant">Select</span> <span class="ident">a</span> <span class="constant">Date</span><span class="punct">&lt;/</span><span class="regex">h1&gt;
      &lt;%= calendar_date_select_tag 
          :current_date, 
          @current_date, 
          {:embedded =&gt; &quot;true&quot;,
           :onchange =&gt; &quot;new Ajax.Updater('current_date_div', '</span><span class="punct">/</span><span class="ident">dashboard</span><span class="punct">/</span><span class="ident">current_date?current_date</span><span class="punct">='</span><span class="string"> + $H({current_date: this.value}).toQueryString(), 
                        {asynchronous:true, evalScripts:true}); 
                        new Ajax.Updater(</span><span class="punct">'</span><span class="ident">time_entries_div</span><span class="punct">'</span><span class="string">, </span><span class="punct">'/</span><span class="ident">dashboard</span><span class="punct">/</span><span class="ident">time_entries?current_date</span><span class="punct">='</span><span class="string"> + $H({current_date: this.value}).toQueryString(),
                        {asynchronous:true, evalScripts:true})&quot;} 
      %&gt;
    &lt;% else -%&gt;
      &lt;h1&gt;[[Help Title]]&lt;/h1&gt;
      &lt;p&gt;[[Help Body]]&lt;/p&gt;
    &lt;% end -%&gt;
  &lt;/div&gt;
&lt;/div&gt; </span></code></pre></div>

<p>Finally we need a create method in the controller to handle the creation of the new time entry when we submit the form:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">create</span>
    <span class="ident">project</span> <span class="punct">=</span> <span class="constant">Project</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:project</span><span class="punct">])</span>
    <span class="ident">projects_activity</span> <span class="punct">=</span> <span class="constant">ProjectsActivity</span><span class="punct">.</span><span class="ident">find</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:projects_activity</span><span class="punct">])</span>
    <span class="attribute">@time_entry</span> <span class="punct">=</span> <span class="constant">TimeEntry</span><span class="punct">.</span><span class="ident">new</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">user</span> <span class="punct">=</span> <span class="ident">current_user</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">project</span> <span class="punct">=</span> <span class="ident">project</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">projects_activity</span> <span class="punct">=</span> <span class="ident">projects_activity</span>
    <span class="ident">start_time</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:start</span><span class="punct">])</span>
    <span class="ident">end_time</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">parse</span><span class="punct">(</span><span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:end</span><span class="punct">])</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">hours</span> <span class="punct">=</span> <span class="ident">params</span><span class="punct">[</span><span class="symbol">:time_entry</span><span class="punct">][</span><span class="symbol">:hours</span><span class="punct">]</span>

    <span class="keyword">unless</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> 
      <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">today</span>
    <span class="keyword">end</span>
    <span class="attribute">@current_date</span> <span class="punct">=</span> <span class="ident">session</span><span class="punct">[</span><span class="symbol">:current_date</span><span class="punct">]</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">start</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">utc</span><span class="punct">(</span><span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">,</span> <span class="ident">start_time</span><span class="punct">.</span><span class="ident">hour</span><span class="punct">,</span> <span class="ident">start_time</span><span class="punct">.</span><span class="ident">min</span><span class="punct">)</span>
    <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">utc</span><span class="punct">(</span><span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">year</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">month</span><span class="punct">,</span> <span class="attribute">@current_date</span><span class="punct">.</span><span class="ident">mday</span><span class="punct">,</span> <span class="ident">end_time</span><span class="punct">.</span><span class="ident">hour</span><span class="punct">,</span> <span class="ident">end_time</span><span class="punct">.</span><span class="ident">min</span><span class="punct">)</span>

    <span class="keyword">if</span> <span class="attribute">@time_entry</span><span class="punct">.</span><span class="ident">save</span>
      <span class="ident">flash</span><span class="punct">[</span><span class="symbol">:notice</span><span class="punct">]</span> <span class="punct">=</span> <span class="punct">'</span><span class="string">TimeEntry was successfully created.</span><span class="punct">'</span>
      <span class="ident">redirect_to</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">index</span><span class="punct">'</span>
    <span class="keyword">else</span>
      <span class="ident">render</span> <span class="symbol">:action</span> <span class="punct">=&gt;</span> <span class="punct">'</span><span class="string">index</span><span class="punct">'</span>
    <span class="keyword">end</span>
  <span class="keyword">end</span></code></pre></div>

<p>In the code above we first find the project and the project activity based on the parameters posted with the form, next we create a new TimeEntry object and set the values on the form. The start and end times on the time entry are calculated using the current_date value and the hour and minutes selected on the time pickers.</p>

<p><img src="/ourblogs/files/tempo_dashboard_sm_01.png" alt="tempo dashboard"/></p>

<p>In the next installment we will move beyond the simple capabilities implemented so far and begin thinking about what it takes to polish a product so that it can be ready for mass consumption. Until the next time.</p>      </div>
    </content>
  </entry>
  <entry>
    <id>tag:www.integrallis.com,:Article/21</id>
    <published>2007-12-20T11:36:10-05:00</published>
    <updated>2007-12-26T11:45:27-05:00</updated>
    <link type="text/html" href="http://www.integrallis.com/ourblogs/articles/2007/12/20/java-6-preview-available-for-leopard" rel="alternate"/>
    <author>
      <name>Joseph Nusairat</name>
    </author>
    <title type="html">Java 6 Preview Available for Leopard</title>
    <category term="java" scheme="http://www.integrallis.com/ourblogs/articles/category/java" label="Java"/>
    <category term="mac" scheme="http://www.integrallis.com/ourblogs/articles/category/mac" label="Mac"/>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>The long awaited news of Java 6 on Leopard has finally been announced, albeit with little fan fare.</p>

<p><a href="http://developer.apple.com/java/">Java 6 on Leopard</a></p>

<p>Apple has released the preview version; meaning a final version should be coming soon. While I find this to be great news for those of us who do Java development on the Mac, I find it intriguing by the fact that it makes special use of 64-bit architecture. However, it's that last part that worries me a bit. Apparently you HAVE to have a Core 2 Duo to use Java 6. So that means myself and two of my business partners Mac laptops will not be able to run Java 6. Now generally developers like to stay on the cutting edge at all times. But really, the Core duos are ONLY a year and a half old? That is NOT that old to have to upgrade. </p>

<p>I guess we shall have to see how desperate the Java developers who use the Mac are. There was a slight alternative right now as well. Someone has ported the unix JDK6 to the Mac with almost complete functionality. (the URL of the site escapes me right now but I will post it when I find it)</p>      </div>
    </summary>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>The long awaited news of Java 6 on Leopard has finally been announced, albeit with little fan fare.</p>

<p><a href="http://developer.apple.com/java/">Java 6 on Leopard</a></p>

<p>Apple has released the preview version; meaning a final version should be coming soon. While I find this to be great news for those of us who do Java development on the Mac, I find it intriguing by the fact that it makes special use of 64-bit architecture. However, it's that last part that worries me a bit. Apparently you HAVE to have a Core 2 Duo to use Java 6. So that means myself and two of my business partners Mac laptops will not be able to run Java 6. Now generally developers like to stay on the cutting edge at all times. But really, the Core duos are ONLY a year and a half old? That is NOT that old to have to upgrade. </p>

<p>I guess we shall have to see how desperate the Java developers who use the Mac are. There was a slight alternative right now as well. Someone has ported the unix JDK6 to the Mac with almost complete functionality. (the URL of the site escapes me right now but I will post it when I find it)</p>      </div>
    </content>
  </entry>
  <entry>
    <id>tag:www.integrallis.com,:Article/20</id>
    <published>2007-12-10T14:21:01-05:00</published>
    <updated>2007-12-10T14:55:19-05:00</updated>
    <link type="text/html" href="http://www.integrallis.com/ourblogs/articles/2007/12/10/year-of-dynamic-java" rel="alternate"/>
    <author>
      <name>Joseph Nusairat</name>
    </author>
    <title type="html">Year of Dynamic Java?</title>
    <category term="java" scheme="http://www.integrallis.com/ourblogs/articles/category/java" label="Java"/>
    <category term="seam" scheme="http://www.integrallis.com/ourblogs/articles/category/seam" label="Seam"/>
    <category term="groovy-grails" scheme="http://www.integrallis.com/ourblogs/articles/category/groovy-grails" label="Groovy"/>
    <category term="Java" scheme="http://www.integrallis.com/ourblogs/articles/tag/java"/>
    <category term="Groovy" scheme="http://www.integrallis.com/ourblogs/articles/tag/groovy"/>
    <category term="Seam" scheme="http://www.integrallis.com/ourblogs/articles/tag/seam"/>
    <category term="Dynamic" scheme="http://www.integrallis.com/ourblogs/articles/tag/dynamic"/>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>Every year brings with it new technologies, this year is of course is no different. One of the biggest changes I have seen this year (which did not really hit ‘till the end of the year) are some of the dynamic language features in Java, specifically Groovy.</p>

<p>Groovy has come a long way and with the 1.5 release over the weekend brings new meta-programming capabilities and better support for DSLs. All of this is supposed to help the Grails framework. And if you have used both you will really see the Ruby influence mixed with Java standards (there are of course many additions since this is a 1.5 release -from 1.0-.</p>

<p>The real power I see is with Groovy's being supported 100% in Grails (of course) and even in JBoss Seam. Besides Seam just being a good tool to bridge the gap between JSF and EJB3 it has quite a bit of support for ease of development when doing jBPM (JBoss' business process management system which can use Drools as part of its decision making process).</p>

<p>I think next year will be interesting to see if (now that the Java dynamic languages have reached good maturity) whether Groovy will really start to grow in the Java community. The NoFluffJustStuff tour has even branched off with a G2 (Groovy and Grails) tour as well.</p>

<p>At any rate, whether you are a Java, Ruby, or Python developer ... the exponential spread in popularity over the last 2 - 3 years of using dynamic languages via DSLs is great for the community. Let's see what 2008 brings.</p>      </div>
    </summary>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p>Every year brings with it new technologies, this year is of course is no different. One of the biggest changes I have seen this year (which did not really hit ‘till the end of the year) are some of the dynamic language features in Java, specifically Groovy.</p>

<p>Groovy has come a long way and with the 1.5 release over the weekend brings new meta-programming capabilities and better support for DSLs. All of this is supposed to help the Grails framework. And if you have used both you will really see the Ruby influence mixed with Java standards (there are of course many additions since this is a 1.5 release -from 1.0-.</p>

<p>The real power I see is with Groovy's being supported 100% in Grails (of course) and even in JBoss Seam. Besides Seam just being a good tool to bridge the gap between JSF and EJB3 it has quite a bit of support for ease of development when doing jBPM (JBoss' business process management system which can use Drools as part of its decision making process).</p>

<p>I think next year will be interesting to see if (now that the Java dynamic languages have reached good maturity) whether Groovy will really start to grow in the Java community. The NoFluffJustStuff tour has even branched off with a G2 (Groovy and Grails) tour as well.</p>

<p>At any rate, whether you are a Java, Ruby, or Python developer ... the exponential spread in popularity over the last 2 - 3 years of using dynamic languages via DSLs is great for the community. Let's see what 2008 brings.</p>      </div>
    </content>
  </entry>
  <entry>
    <id>tag:www.integrallis.com,:Article/19</id>
    <published>2007-12-06T20:36:09-05:00</published>
    <updated>2007-12-07T12:42:26-05:00</updated>
    <link type="text/html" href="http://www.integrallis.com/ourblogs/articles/2007/12/06/building-tempo-with-rails-part-v" rel="alternate"/>
    <author>
      <name>Brian Sam-Bodden</name>
    </author>
    <title type="html">Building Tempo with Rails, Part V</title>
    <category term="ruby" scheme="http://www.integrallis.com/ourblogs/articles/category/ruby" label="Ruby"/>
    <category term="rails" scheme="http://www.integrallis.com/ourblogs/articles/category/rails" label="Rails"/>
    <category term="Rails" scheme="http://www.integrallis.com/ourblogs/articles/tag/rails"/>
    <category term="Ruby" scheme="http://www.integrallis.com/ourblogs/articles/tag/ruby"/>
    <category term="agile" scheme="http://www.integrallis.com/ourblogs/articles/tag/agile"/>
    <summary type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p><img src="/ourblogs/files/rails.png" alt="Rails"/></p>

<p>This installment was supposed to be about building the Dashboard page of the Tempo application. Instead, I'm addressing some bugs reported by readers.</p>

<h2>Fixing Bugs TDD-style</h2>

<p>An observant reader pointed out that one of the tests for the TimeEntry class broke when testing using a date range across a month boundary.</p>

<p>The offending code is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">split!</span>
    <span class="ident">remaining_time_entries</span> <span class="punct">=</span> <span class="punct">[]</span>
    <span class="keyword">if</span> <span class="ident">needs_splitting</span>
      <span class="comment"># save the original end time</span>
      <span class="ident">original_end</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span> 
      <span class="comment"># first change the current TimeEntry to the end_of_day of the start day</span>
      <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">change</span><span class="punct">(</span><span class="symbol">:hour</span> <span class="punct">=&gt;</span> <span class="number">23</span><span class="punct">,</span> <span class="symbol">:min</span> <span class="punct">=&gt;</span> <span class="number">59</span><span class="punct">,</span> <span class="symbol">:sec</span> <span class="punct">=&gt;</span> <span class="number">59</span><span class="punct">)</span>
      <span class="punct">(</span><span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">day</span><span class="punct">+</span><span class="number">1</span><span class="punct">..</span><span class="ident">original_end</span><span class="punct">.</span><span class="ident">day</span><span class="punct">).</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">day</span><span class="punct">|</span>
        <span class="ident">time_entry</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">clone</span>
        <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span> <span class="punct">=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">change</span><span class="punct">(</span><span class="symbol">:mday</span> <span class="punct">=&gt;</span> <span class="ident">day</span><span class="punct">).</span><span class="ident">beginning_of_day</span>
        <span class="keyword">if</span> <span class="ident">day</span> <span class="punct">==</span> <span class="ident">original_end</span><span class="punct">.</span><span class="ident">day</span>
          <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="ident">original_end</span>
        <span class="keyword">else</span>
          <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">change</span><span class="punct">(</span><span class="symbol">:hour</span> <span class="punct">=&gt;</span> <span class="number">23</span><span class="punct">,</span> <span class="symbol">:min</span> <span class="punct">=&gt;</span> <span class="number">59</span><span class="punct">,</span> <span class="symbol">:sec</span> <span class="punct">=&gt;</span> <span class="number">59</span><span class="punct">)</span>
        <span class="keyword">end</span>
        <span class="ident">remaining_time_entries</span> <span class="punct">&lt;&lt;</span> <span class="ident">time_entry</span>
      <span class="keyword">end</span>   
    <span class="keyword">end</span>
    <span class="ident">remaining_time_entries</span>
  <span class="keyword">end</span></code></pre></div>

<p>Even though the code above was created in a TDD fashion and several of the tests created exercised the code, the tests failed to cover all of the possible cases.</p>

<p>The lesson here is that when dealing with date ranges, you should test across months and year boundaries. The code above only works when the two datetimes are in the same month and year which is a critical flaw. The code uses the day method to loop form the start day to the end day of the range.  This will obviously break across months and of course across years.</p>

<p>One good thing about the test above was (as some might argue whether this is a good thing or not) is that I used a date range that started on the current date and time. In a continuous integration scenario this broken test would had revealed itself in the hourly build.</p>

<p>I've also made the same mistake (of using the day method) to check if a range of dates needed splitting, here's the original code:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="keyword">def </span><span class="method">needs_splitting</span>
  <span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">day</span> <span class="punct">&lt;</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span><span class="punct">.</span><span class="ident">day</span>
<span class="keyword">end</span></code></pre></div>

<p>First, let's prove that the code is indeed broken. To accomplish this I've written a test that crosses a month boundary:</p>

<div class="typocode"><pre><code class="typocode_ruby "><span class="ident">it</span> <span class="punct">&quot;</span><span class="string">should know how to split a time entry across multiple days over a month boundary</span><span class="punct">&quot;</span> <span class="keyword">do</span>
  <span class="ident">time_entry</span> <span class="punct">=</span> <span class="ident">create_time_entry</span>
  <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span> <span class="punct">=</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">local</span><span class="punct">(</span><span class="number">2007</span><span class="punct">,&quot;</span><span class="string">nov</span><span class="punct">&quot;,</span><span class="number">30</span><span class="punct">,</span><span class="number">23</span><span class="punct">,</span><span class="number">0</span><span class="punct">,</span><span class="number">0</span><span class="punct">)</span>
  <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="number">5</span><span class="punct">.</span><span class="ident">hours</span><span class="punct">.</span><span class="ident">since</span><span class="punct">(</span><span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span><span class="punct">)</span>
  <span class="ident">entries</span> <span class="punct">=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">split!</span>
  <span class="ident">entries</span><span class="punct">.</span><span class="ident">should_not</span> <span class="ident">be_empty</span>
  <span class="ident">total</span> <span class="punct">=</span> <span class="number">0.0</span>
  <span class="ident">entries</span><span class="punct">.</span><span class="ident">inject</span><span class="punct">(</span><span class="number">0</span><span class="punct">)</span> <span class="punct">{|</span><span class="ident">total</span><span class="punct">,</span> <span class="ident">e</span><span class="punct">|</span> <span class="ident">total</span> <span class="punct">+=</span> <span class="ident">e</span><span class="punct">.</span><span class="ident">total_hours</span><span class="punct">}</span>
  <span class="ident">total</span> <span class="punct">+=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">total_hours</span>
  <span class="ident">total</span><span class="punct">.</span><span class="ident">should</span> <span class="ident">eql</span><span class="punct">(</span><span class="number">5.0</span><span class="punct">)</span>
  <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">needs_splitting</span><span class="punct">.</span><span class="ident">should_not</span> <span class="ident">be_true</span>
<span class="keyword">end</span></code></pre></div>

<p>The above test fails with the existing code. Now we can refactor the code to pass the test. </p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">needs_splitting</span>    
    <span class="punct">(</span><span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">year</span> <span class="punct">!=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span><span class="punct">.</span><span class="ident">year</span><span class="punct">)</span> <span class="punct">||</span>
    <span class="punct">(</span><span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">month</span> <span class="punct">!=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span><span class="punct">.</span><span class="ident">month</span><span class="punct">)</span> <span class="punct">||</span>
    <span class="punct">(</span><span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">day</span> <span class="punct">!=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span><span class="punct">.</span><span class="ident">day</span><span class="punct">)</span> 
  <span class="keyword">end</span>

  <span class="keyword">def </span><span class="method">split!</span>
    <span class="ident">remaining_time_entries</span> <span class="punct">=</span> <span class="punct">[]</span>
    <span class="keyword">if</span> <span class="ident">needs_splitting</span>
      <span class="comment"># save the original end time</span>
      <span class="ident">original_end</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span> 
      <span class="comment"># first change the current TimeEntry to the end_of_day of the start day</span>
      <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="ident">end_of_day</span><span class="punct">(</span><span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">)</span>
      <span class="ident">days</span> <span class="punct">=</span> <span class="punct">((</span><span class="ident">original_end</span> <span class="punct">-</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">)</span> <span class="punct">/</span> <span class="number">86400</span><span class="punct">).</span><span class="ident">ceil</span><span class="punct">.</span><span class="ident">to_i</span>  
      <span class="punct">(</span><span class="number">1</span><span class="punct">..</span><span class="ident">days</span><span class="punct">).</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">day</span><span class="punct">|</span>
        <span class="ident">time_entry</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">clone</span>
        <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span> <span class="punct">=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">advance</span><span class="punct">(</span><span class="symbol">:days</span> <span class="punct">=&gt;</span> <span class="ident">day</span><span class="punct">).</span><span class="ident">beginning_of_day</span>
        <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span><span class="punct">.</span><span class="ident">advance</span><span class="punct">(</span><span class="symbol">:days</span> <span class="punct">=&gt;</span> <span class="ident">day</span><span class="punct">)</span>
        <span class="keyword">if</span> <span class="ident">same_day</span><span class="punct">(</span><span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span><span class="punct">,</span> <span class="ident">original_end</span><span class="punct">)</span>
          <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span><span class="punct">.</span><span class="ident">change</span><span class="punct">(</span><span class="symbol">:hour</span> <span class="punct">=&gt;</span> <span class="ident">original_end</span><span class="punct">.</span><span class="ident">hour</span><span class="punct">,</span> <span class="symbol">:min</span> <span class="punct">=&gt;</span> <span class="ident">original_end</span><span class="punct">.</span><span class="ident">min</span><span class="punct">,</span> <span class="symbol">:sec</span> <span class="punct">=&gt;</span> <span class="ident">original_end</span><span class="punct">.</span><span class="ident">sec</span><span class="punct">)</span>   
        <span class="keyword">else</span>
          <span class="ident">time_entry</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="ident">end_of_day</span><span class="punct">(</span><span class="ident">time_entry</span><span class="punct">.</span><span class="ident">start</span><span class="punct">)</span>
        <span class="keyword">end</span>
        <span class="ident">remaining_time_entries</span> <span class="punct">&lt;&lt;</span> <span class="ident">time_entry</span>
      <span class="keyword">end</span>   
    <span class="keyword">end</span>
    <span class="ident">remaining_time_entries</span>
  <span class="keyword">end</span></code></pre></div>

<p>The needs_splitting method now checks the year, month and day. The split! method now finds the total number of whole days (plus one) in the datetime range. It then creates new TimeEntry(s) for each of the whole days (24 hours each) and a partial one of the last day on the range. To advance each one of the days I use the advance method (see Rails extensions to the Time class).</p>      </div>
    </summary>
    <content type="xhtml">
      <div xmlns="http://www.w3.org/1999/xhtml">
<p><img src="/ourblogs/files/rails.png" alt="Rails"/></p>

<p>This installment was supposed to be about building the Dashboard page of the Tempo application. Instead, I'm addressing some bugs reported by readers.</p>

<h2>Fixing Bugs TDD-style</h2>

<p>An observant reader pointed out that one of the tests for the TimeEntry class broke when testing using a date range across a month boundary.</p>

<p>The offending code is shown below:</p>

<div class="typocode"><pre><code class="typocode_ruby ">  <span class="keyword">def </span><span class="method">split!</span>
    <span class="ident">remaining_time_entries</span> <span class="punct">=</span> <span class="punct">[]</span>
    <span class="keyword">if</span> <span class="ident">needs_splitting</span>
      <span class="comment"># save the original end time</span>
      <span class="ident">original_end</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span> 
      <span class="comment"># first change the current TimeEntry to the end_of_day of the start day</span>
      <span class="constant">self</span><span class="punct">.</span><span class="ident">end</span> <span class="punct">=</span> <span class="constant">self</span><span class="punct">.</span><span class="ident">start</span><span class="punct">.</span><span class="ident">change</span><span class="punct">(</span><span 