<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Sterling Rose Design Blog</title>
    <link>http://www.sterlingrosedesign.com/posts/rss</link>
    <description>Code snippets, observations, and opinions about Ruby on Rails from a web developer in Indiana, US</description>
    <language>en-us</language>
    <item>
      <title>Freelancing: Writing Estimates</title>
      <description>I get asked this question a lot: How do you write a proposal for a freelance contract development job?&lt;br /&gt;
&lt;br /&gt;
First, it&amp;#8217;s important to understand that freelancing is a different animal from working for a larger development firm (or, as I lovingly think of them, a Dev-in-a-Box). We have some considerations as independents that they don&amp;#8217;t, and vice versa, so I don&amp;#8217;t presume to know how best to bid jobs if you&amp;#8217;re the Thoughtbots or Hashrockets of the world.&lt;br /&gt;
&lt;br /&gt;
But if you&amp;#8217;re an independent developer, then these tips may be useful for you.&lt;br /&gt;
&lt;br /&gt;
1) Never, ever, ever bid flat-rate. Nobody is that good at estimating the time it takes to develop an application, and you will almost surely be wildly over or wildly under the amount of hours it takes you. Also, the client who knows you aren&amp;#8217;t going over $X will tack on as many new features to the spec as you will allow them to, since they know it can&amp;#8217;t cost them any more. Someone always gets screwed in fixed-bid development, and it&amp;#8217;s usually the developer.&lt;br /&gt;
&lt;br /&gt;
2) Make it clear to your client that your estimate is just that &amp;#8211; you may be under or over your amount. The client should be able to have a number in their head, but also they need to understand that it might not be &lt;em&gt;the&lt;/em&gt; number. Mine say, &amp;#8220;I have given what I believe to be worst-case scenarios at each stage, though it should be understood that these are only estimates &amp;#8211; actual completion times could be less or more than what is shown for any phase, as we understand the requirements in more detail.&amp;#8221; Which leads us into&amp;#8230;&lt;br /&gt;
&lt;br /&gt;
3) Phases. I like to break a job out into phases, with upper and lower time estimates for each phase. Not only does this help you think more meaningfully about what a project entails, it lets the client know where all that money is going. If they are keeping their overall budget close to the vest, then they can look at the phases and get a guesstimate of how far down the phase list their budget will stretch, and whether that&amp;#8217;s a reasonable investment for them.&lt;br /&gt;
&lt;br /&gt;
4) Don&amp;#8217;t undercut your rate. Almost every developer I have talked to about this has a rate &lt;em&gt;range&lt;/em&gt;, rather than an absolute rate. The hourly figure you quote for any particular job depends on the complexity of the work, the amount of code you will be able to reuse from other projects vs. the amount you will have to write from scratch, the amount of new tools/skills you will have to learn to deliver the project, the number of referrals you think you might get from the client, how difficult the client is to work with, what the market is like at the time, and how badly you need the work. In the last two months, I have bid projects at the absolute low end of my rate, and at the (current) absolute high end of my rate. Some I&amp;#8217;ve landed, and some I haven&amp;#8217;t, but I feel good about the rates I&amp;#8217;ve given out in every case.&lt;br /&gt;
&lt;br /&gt;
5) Be sure the client understands that any training (them of you or you of them), client phone calls, and the like are billable hours. Add it into the estimate (the amount depends on how long the project will take overall, but usually at least an hour a week).&lt;br /&gt;
&lt;br /&gt;
6) This is one area in which I know some developers will disagree with me, as we&amp;#8217;ve had discussions of it on &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt;. I do not bill the client for the time it takes me to learn new technologies or techniques. I recently needed to learn a little Prototype to deliver some nifty interactive goodness on a project. I had to read some of the Prototype &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;, watch a couple of Railscasts, and read several blog entries. None of that time is billable. I&amp;#8217;m perfectly willing to bill a client for the time it takes to figure out how to &lt;em&gt;apply&lt;/em&gt; something to their particular needs, but billing them for me learning something that is reusable feels like robbery.&lt;br /&gt;
&lt;br /&gt;
7) Put an &amp;#8220;expires by&amp;#8221; date on your proposal. Your rates should naturally increase over time as your reputation grows and your skillset improves. You don&amp;#8217;t want to have to explain to a client a year or two after you submit an estimate to them why you can no longer honor the rate you quoted. I usually give the estimate a lifespan of anything from one to three months.&lt;br /&gt;
&lt;br /&gt;
8) Spell out whether hosting is included or not. If you anticipate any other, outside costs (logo design, image manipulation, whatever) be sure to explain that in your estimate.&lt;br /&gt;
&lt;br /&gt;
9) Submit estimates promptly after meeting with (virtually or in person) the client. You want the information fresh in your mind, and you want the client to know that you deliver promptly. I usually have a written estimate in the customer&amp;#8217;s hand within 24 hours.&lt;br /&gt;
&lt;br /&gt;
10) And now, the hardest part &amp;#8211; how much time to attach to each phase? I do not have any magic answers to this. To be honest, I&amp;#8217;m not that great at estimating time. I wrote a proposal once that a particular phase would take me 2 hours. It took 15 minutes. In that same proposal, I estimated something would take 30 hours. I&amp;#8217;m at hour 42 as I write this, and it&amp;#8217;s still not done. The general rule of thumb is to take the most you think it could take, and multiply it by 2.5. Even then, the sad truth is that it&amp;#8217;s something of a crap shoot, especially when you get into really complex applications. That is why you never, ever bid fixed-bid. When you get to the point where you&amp;#8217;re approaching the upper limit of what you&amp;#8217;ve estimated and you&amp;#8217;re nowhere close to done, then you have to make a hard choice: Do you tell the client you&amp;#8217;re going to go wildly over-budget and hope they just understand? Do you suck up the extra hours and consider it an investment in your career? Split the difference? That decision depends on your particular client and circumstances, and might be best left for a different blog entry.</description>
      <pubDate>June 04, 2009 14:34</pubDate>
      <link>/posts/freelancing-writing-estimates</link>
      <guid>/posts/freelancing-writing-estimates</guid>
    </item>
    <item>
      <title>Dynamic form with a many-to-many relationship</title>
      <description>My customer&amp;#8217;s application is an in-house ordering system (among other things). The order form has a drop-down list to select the client placing the order. It also has two other drop-down lists: primary_contact_id and secondary_contact_id, both of which are based on the Contact model. My customer is certain he will only ever need to associate two contacts with an order, so I&amp;#8217;m comfortable with this approach.&lt;br /&gt;
&lt;br /&gt;
The sticking point was that I only want to populate the primary and secondary contact select boxes with contacts that are associated with a particular client. Client and Contact have a many-to-many association.&lt;br /&gt;
&lt;br /&gt;
Ryan Bates&amp;#8217; &lt;a href=&quot;http://media.railscasts.com/videos/088_dynamic_select_menus.mov&quot;&gt;Dynamic Select Menus Railscast&lt;/a&gt; got me most of the way there, but his example (countries/states) was one-to-many, not many-to-many. Following was my adaptation:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;views/javascripts/dynamic_contacts.js.erb

var contacts = new Array();
&amp;lt;% for contact in @contacts -%&amp;gt;
  &amp;lt;% for client in contact.clients %&amp;gt;
    contacts.push(new Array(&amp;lt;%= client.id %&amp;gt;, '&amp;lt;%=h contact.name %&amp;gt;', &amp;lt;%= contact.id %&amp;gt;));
  &amp;lt;% end -%&amp;gt;
&amp;lt;% end -%&amp;gt;

function clientSelected() {
  client_id = $('order_client_id').getValue();
  options = $('order_primary_contact_id').options;
  options2 = $('order_secondary_contact_id').options;
  options.length = 1;
  options2.length = 1;
  contacts.each(function(contact) {
    if (contact[0] == client_id) {
      options[options.length] = new Option(contact[1], contact[2]);
      options2[options2.length] = new Option(contact[1], contact[2]);
    }
  });
  if (options.length == 1) {
    $('contact_fields').hide();
  } else {
    $('contact_fields').show();
  }
}

document.observe('dom:loaded', function() {
  $('contact_fields').hide();
  $('order_client_id').observe('change', clientSelected);
});&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;views/orders/_form.html.erb

&amp;lt;% javascript 'dynamic_contacts' %&amp;gt;
...
&amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;%= f.label :client_id, &quot;Customer&quot; %&amp;gt;&amp;lt;/strong&amp;gt; &amp;lt;%= f.select :client_id, 
  @clients.map {|c| [c.name, c.id]}, {:prompt =&amp;gt; &quot;Select a Customer&quot;} %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;div id=&quot;contact_fields&quot;&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= f.label :primary_contact_id, &quot;Primary Contact&quot; %&amp;gt; &amp;lt;%= f.select 
    :primary_contact_id, @contacts.map {|c| [c.name, c.id]}, :prompt =&amp;gt; &quot;Select the 
    Primary Contact&quot; %&amp;gt;&amp;lt;/p&amp;gt;
  &amp;lt;p&amp;gt;&amp;lt;%= f.label :secondary_contact_id, &quot;Secondary Contact&quot; %&amp;gt; &amp;lt;%= f.select 
    :secondary_contact_id, @contacts.map {|c| [c.name, c.id]}, :prompt =&amp;gt; &quot;Select the 
    Secondary Contact&quot; %&amp;gt;&amp;lt;/p&amp;gt;
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;controllers/javascripts_controller.rb

def dynamic_contacts
  @contacts = Contact.all
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;helpers/application_helper.rb

def javascript(*files)
  content_for(:head) { javascript_include_tag(*files) }
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
So that&amp;#8217;s it in a nutshell. Most of the code is Ryan&amp;#8217;s (and huge thanks to him for all his help along the way), but there are enough tweaks I thought it warranted documenting.</description>
      <pubDate>May 30, 2009 00:57</pubDate>
      <link>/posts/dynamic-form-with-a-many-to-many-relationship</link>
      <guid>/posts/dynamic-form-with-a-many-to-many-relationship</guid>
    </item>
    <item>
      <title>Web Design Resources</title>
      <description>I don&amp;#8217;t consider myself a designer &amp;#8211; I self-identify as a developer &amp;#8211; but since I&amp;#8217;m the only coder on most of my projects, I have to fake it sometimes. Over the years, I have bookmarked a lot of sites that I find more useful than others in doing the design work. They include:&lt;br /&gt;
&lt;br /&gt;
* &lt;a href=&quot;http://www.bazaardesigns.com/&quot;&gt;Bazaar Designs&lt;/a&gt; &amp;#8211; Links to incredibly rich, detailed stock photos and really unusual font choices available for download and use, as well as great tutorials and blog entries on other subjects, like &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt; and &lt;span class=&quot;caps&quot;&gt;AJAX&lt;/span&gt;.&lt;br /&gt;
* &lt;a href=&quot;http://www.colourlovers.com/&quot;&gt;COLOURlovers&lt;/a&gt; &amp;#8211; Suggestions of color palettes to use for site designs, plus downloadable tiling patterns.&lt;br /&gt;
* &lt;a href=&quot;http://www.dabuttonfactory.com/&quot;&gt;Da Button Factory&lt;/a&gt; &amp;#8211; Generate custom buttons on the fly for use in your applications.&lt;br /&gt;
* &lt;a href=&quot;http://dryicons.com/free-icons/&quot;&gt;Dry Icons&lt;/a&gt; &amp;#8211; Lots and lots of free-to-use glossy icon sets.&lt;br /&gt;
* &lt;a href=&quot;http://www.famfamfam.com/lab/icons/&quot;&gt;FamFamFam Icons&lt;/a&gt; &amp;#8211; These tiny little icons are ubiquitous in web applications. They&amp;#8217;re cute and plentiful, and I use them in almost every website.&lt;br /&gt;
* &lt;a href=&quot;http://www.fontspace.com/&quot;&gt;Fontspace&lt;/a&gt; &amp;#8211; My go-to free fonts place.&lt;br /&gt;
* &lt;a href=&quot;http://www.forwebdesigners.com/&quot;&gt;For Web Designers&lt;/a&gt; &amp;#8211; A plethora of information; links to everything from &lt;span class=&quot;caps&quot;&gt;CSS&lt;/span&gt;-compliant layout templates to font resources to free downloadable fonts to stock photos you can use. It&amp;#8217;s like a giant web-design clearinghouse.&lt;br /&gt;
* &lt;a href=&quot;http://www.lipsum.com/&quot;&gt;Lorem ipsum generator&lt;/a&gt; You often can&amp;#8217;t judge how a site will look without some textual content in it, and &amp;#8220;asdf asdf asdf&amp;#8221; only gets you so far. This site lets you pick the number of paragraphs, words, bytes, or lists you want and generates &amp;#8220;lorem ipsum&amp;#8221; text for you.&lt;br /&gt;
* &lt;a href=&quot;http://pics.tech4learning.com/&quot;&gt;Pics4Learning&lt;/a&gt; &amp;#8211; Stock photos that are free to use &lt;strong&gt;if&lt;/strong&gt; your application is educational.&lt;br /&gt;
</description>
      <pubDate>May 27, 2009 14:48</pubDate>
      <link>/posts/web-design-resources</link>
      <guid>/posts/web-design-resources</guid>
    </item>
    <item>
      <title>Calculating Line Item Extensions</title>
      <description>In my project, I have orders, and each order can have an unlimited number of line_items. Line_items are created by the user clicking on a button, which appends (via &lt;span class=&quot;caps&quot;&gt;RJS&lt;/span&gt;) a new row to the line_items tabled form. So far, so good.&lt;br /&gt;
&lt;br /&gt;
But I needed the extended price (quantity * price_per) of each line_item to be calculated every time the user tabbed out or clicked away from the price_per field. Further, I needed the subtotal, tax, total, and balance fields to be automatically re-calculated.&lt;br /&gt;
&lt;br /&gt;
I messed around with it for several hours, trying Javascript, Prototype, and even jQuery, before I finally settled on a Prototype approach that worked. The real struggle was that using Rails 2.3&amp;#8217;s nested forms functionality meant that each line_item would have an index key embedded in the middle of the text field&amp;#8217;s name and id, and I could not come up with a good way to extract it, to pass it to the Javascript function.&lt;br /&gt;
&lt;br /&gt;
Luckily, the numbering appears to be a 0-based index, so I cheated and used an incrementer.&lt;br /&gt;
&lt;br /&gt;
I know it&amp;#8217;s not a perfect solution (it&amp;#8217;s obtrusive, it&amp;#8217;s probably much more verbose than it needs to be) but it functions.&lt;br /&gt;
&lt;br /&gt;
So, on to the code. Obviously, I&amp;#8217;ve snipped out a lot of stuff that doesn&amp;#8217;t have anything to do with this example.&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/controllers/orders_controller.rb

def new
  @order = Order.new
  @order.line_items.build
  @order.zero_set_amounts
  @colors = Color.unremoved
end

def edit
  @order = Order.new
  @colors = Color.unremoved
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/models/order.rb

def zero_set_amounts
  self.subtotal = 0
  self.tax = 0
  self.shipping = 0
  self.artwork = 0
  self.setup = 0
  self.printing_charge = 0
  self.misc_charge = 0
  self.total = 0
  self.balance = 0
  self.reorder ||= false
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/views/layouts/application.html.erb

&amp;lt;head&amp;gt;
  &amp;lt;%= javascript_include_tag :defaults, 'main' %&amp;gt;
&amp;lt;/head&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/views/orders/new.html.erb and /views/orders/edit.html.erb

&amp;lt;% form_for(@order) do |f| %&amp;gt;
  &amp;lt;%= render :partial =&amp;gt; &quot;form&quot;, :locals =&amp;gt; {:f =&amp;gt; f} %&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/views/orders/_form.html.erb

&amp;lt;div id=&quot;order_line_items&quot;&amp;gt;
  &amp;lt;%= render :partial =&amp;gt; 'line_items', :locals =&amp;gt; {:f =&amp;gt; f, :order =&amp;gt; @order} %&amp;gt;
  &amp;lt;div id=&quot;order_summary_fields&quot;&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :subtotal %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= text_field_tag :subtotal, 0, :size =&amp;gt; 10, 
      :disabled =&amp;gt; true %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :artwork %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= f.text_field :artwork, :size =&amp;gt; 10, :onblur =&amp;gt; 
      'recalculateTotals();' %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :setup %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= f.text_field :setup, :size =&amp;gt; 10, :onblur =&amp;gt; 
      'recalculateTotals();' %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :printing_charge, &quot;Printing&quot; %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= f.text_field :printing_charge, :size =&amp;gt; 10, :onblur =&amp;gt; 
      'recalculateTotals();' %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :misc_charge, &quot;Miscellaneous&quot; %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= f.text_field :misc_charge, :size =&amp;gt; 10, :onblur =&amp;gt; 
      'recalculateTotals();' %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :shipping %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= f.text_field :shipping, :size =&amp;gt; 10, :onblur =&amp;gt; 
      'recalculateTotals();' %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :tax %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= text_field_tag :tax, 0, :size =&amp;gt; 10, :disabled =&amp;gt; true %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;strong&amp;gt;&amp;lt;%= f.label :total %&amp;gt;&amp;lt;/strong&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= text_field_tag :total, 0, :size =&amp;gt; 10, 
      :disabled =&amp;gt; true %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;left&quot;&amp;gt;&amp;lt;%= f.label :balance %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;div class=&quot;right&quot;&amp;gt;&amp;lt;%= text_field_tag :balance, 0, :size =&amp;gt; 10, 
      :disabled =&amp;gt; true %&amp;gt;&amp;lt;/div&amp;gt;
    &amp;lt;%= render :partial =&amp;gt; &quot;shared/create_or_update&quot;, :locals =&amp;gt; {:f =&amp;gt; f} %&amp;gt;
    &amp;lt;%= f.hidden_field :subtotal %&amp;gt;
    &amp;lt;%= f.hidden_field :tax %&amp;gt;
    &amp;lt;%= f.hidden_field :total %&amp;gt;
    &amp;lt;%= f.hidden_field :balance%&amp;gt;
    &amp;lt;%= f.hidden_field :reorder %&amp;gt;
  &amp;lt;/div&amp;gt;  
&amp;lt;/div&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/views/order/_line_items.html.erb

&amp;lt;%= button_to_remote 'Add a New Line Item', {:url =&amp;gt; new_line_item_path, :method =&amp;gt; :get} %&amp;gt;
...
&amp;lt;% i = 0 %&amp;gt;
&amp;lt;% f.fields_for :line_items do |line_items_forms| %&amp;gt;
  &amp;lt;tr&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= line_items_forms.text_field :quantity, :size =&amp;gt; 5 %&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= line_items_forms.text_field :description, :size =&amp;gt; 30 %&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= line_items_forms.select :color_id, @colors.map {|c| [c.name, c.id]} %&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= line_items_forms.text_field :price_per, :size =&amp;gt; 10, :onblur =&amp;gt; 
      order.new_record? ? 'updateExtendedPrice(&quot;order_line_items_attributes_0_quantity&quot;, 
      this.id, &quot;order_line_items_attributes_0_price_extended&quot;);' : 
      &quot;updateExtendedPrice('order_line_items_attributes_#{i}_quantity', this.id, 
      'order_line_items_attributes_#{i}_price_extended');&quot; %&amp;gt;&amp;lt;/td&amp;gt;
    &amp;lt;td&amp;gt;&amp;lt;%= line_items_forms.text_field :price_extended, :size =&amp;gt; 10, :class =&amp;gt; 
      'fluffy_bunny' %&amp;gt;&amp;lt;/td&amp;gt;
   &amp;lt;% i += 1 %&amp;gt;
  &amp;lt;/tr&amp;gt;
&amp;lt;% end %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
Yeah, I called my class &amp;#8220;fluffy_bunny.&amp;#8221; It&amp;#8217;s not a class name I was likely to use anywhere else, and fluffy bunnies are cute. :)&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/controllers/line_items_controller.rb

def new    
  begin
    @order = Order.find(params[:order_id])
    @line_item = @order.line_items.build
  rescue ActiveRecord::RecordNotFound
    @line_item = LineItem.new
  ensure
    @item_index = @order.nil? ? Time.now.to_i : (@order.line_items.length - 1)
  end

  respond_to do |format|
    format.html
    format.js do        
      @colors = Color.unremoved.collect {|c| [c.name, c.id]}
      @line_id = &quot;order_line_items_attributes_#{@item_index}&quot;
      @line_name = &quot;order[line_items_attributes][#{@item_index}]&quot;
    end
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/views/line_items/new.js.erb

$('line_item_table').insert(&amp;lt;%=js render(:partial =&amp;gt; &quot;new_line_item&quot;) %&amp;gt;, 'bottom');&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/views/line_items/_new_line_item.html.erb

&amp;lt;tr&amp;gt; 
  &amp;lt;td&amp;gt;&amp;lt;%= text_field_tag &quot;#{@line_id}_quantity&quot;, '', :name =&amp;gt; &quot;#{@line_name}[quantity]&quot;, 
    :size =&amp;gt; 5 -%&amp;gt;&amp;lt;/td&amp;gt; 
  &amp;lt;td&amp;gt;&amp;lt;%= text_field_tag &quot;#{@line_id}_description&quot;, '', :name =&amp;gt; 
    &quot;#{@line_name}[description]&quot;, :size =&amp;gt; 30 -%&amp;gt;&amp;lt;/td&amp;gt; 
  &amp;lt;td&amp;gt;&amp;lt;%= select_tag &quot;#{@line_id}_color_id&quot;, options_for_select(@colors), :name =&amp;gt; 
    &quot;#{@line_name}[color_id]&quot; -%&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= text_field_tag &quot;#{@line_id}_price_per&quot;, '', :name =&amp;gt; 
    &quot;#{@line_name}[price_per]&quot;, :size =&amp;gt; 10, :onblur =&amp;gt; 
    &quot;updateExtendedPrice('order_line_items_attributes_#{@item_index}_quantity', this.id, 
    'order_line_items_attributes_#{@item_index}_price_extended');&quot; -%&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= text_field_tag &quot;#{@line_id}_price_extended&quot;, '', :name =&amp;gt; 
    &quot;#{@line_name}[price_extended]&quot;, :size =&amp;gt; 10, :class =&amp;gt; 'fluffy_bunny' -%&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;/public/javascripts/main.js

function updateExtendedPrice(x,y,z) {
  $(z).value=parseFloat($(x).value) * parseFloat($(y).value);
  updateSubtotal();
  recalculateTotals();
}

function updateSubtotal() {
  var subtotal=0;
  var li;
  var line_item_extensions = $$('.fluffy_bunny');
  line_item_extensions.each(function(li) {subtotal += parseFloat(li.value);})
  $('order_subtotal').value=subtotal;
  $('subtotal').value=subtotal;
}

function updateTax() {
  /* Tax rate is 7% */
  var tax = ((parseFloat($('order_subtotal').value) + 
    parseFloat($('order_artwork').value) + parseFloat($('order_setup').value) + 
    parseFloat($('order_shipping').value) + parseFloat($('order_printing_charge').value) 
    + parseFloat($('order_misc_charge').value)) * 0.07).toFixed(2);
  $('order_tax').value=tax;
  $('tax').value=tax;
}

function updateTotal() {
  var total = (parseFloat($('order_subtotal').value) + 
  parseFloat($('order_artwork').value) + parseFloat($('order_setup').value) + 
  parseFloat($('order_tax').value) + parseFloat($('order_shipping').value) + 
  parseFloat($('order_printing_charge').value) + 
    parseFloat($('order_misc_charge').value)).toFixed(2);
  $('order_total').value=total;
  $('total').value=total;
}

function updateBalance() {
  balance = $('order_total').value;
  $('order_balance').value = balance;
  $('balance').value = balance;
}

function recalculateTotals() {
  updateTax();
  updateTotal();
  updateBalance();
}&lt;/code&gt;&lt;/pre&gt;</description>
      <pubDate>May 25, 2009 14:48</pubDate>
      <link>/posts/calculating-line-item-extensions</link>
      <guid>/posts/calculating-line-item-extensions</guid>
    </item>
    <item>
      <title>assert_include Workaround</title>
      <description>I&amp;#8217;m not sure if there used to be an assert_include method or not (I&amp;#8217;ve seen some references to it, but can&amp;#8217;t find it anywhere in &lt;a href=&quot;http://apidock.com/rails&quot;&gt;the Rails &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt;&lt;/a&gt;), but I found a workaround.&lt;br /&gt;
&lt;br /&gt;
I have a Color model, and I want the :index action to only show those colors whose deleted value is set to false (it&amp;#8217;s more or less what the acts_as_paranoid plugin did/does). My test for the :index action looks like this:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;test &quot;should get only colors that are not deleted&quot; do
  first_color = Color.create(:name =&amp;gt; 'Blue', :deleted =&amp;gt; false)
  second_color = Color.create(:name =&amp;gt; 'Red', :deleted =&amp;gt; true)
  get :index

  assert_response :success
  assert_not_nil assigns(:colors)
  assert_equal true, assigns(:colors).include?(first_color)
  assert_equal false, assigns(:colors).include?(second_color)
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
There may be other ways to do this (and I certainly welcome comments about that, since I&amp;#8217;m pretty new to testing), but it worked for me.</description>
      <pubDate>May 21, 2009 13:51</pubDate>
      <link>/posts/assert-include-workaround</link>
      <guid>/posts/assert-include-workaround</guid>
    </item>
    <item>
      <title>Model Component Ordering</title>
      <description>On a whim, I asked (in &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; and via Twitter) what order &amp;#8211; given &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/Validations/ClassMethods.html#M001047&quot;&gt;validators&lt;/a&gt;, &lt;a href=&quot;http://www.ruby-doc.org/core/classes/Module.html#M001701&quot;&gt;accessors&lt;/a&gt;, and &lt;a href=&quot;http://api.rubyonrails.org/classes/ActiveRecord/Associations/ClassMethods.html#M000981&quot;&gt;associations&lt;/a&gt; &amp;#8211; developers typically listed these components in their models. As far as I know there is no compelling reason to use one order over the other (but feel free to correct me in the comments). Even so, it can be fun to know what other developers do.&lt;br /&gt;
&lt;br /&gt;
I had 19 responses, broken down as follows:&lt;br /&gt;
&lt;br /&gt;
Accessors | Associations | Validators = 20%&lt;br /&gt;
Accessors | Validators | Associations = 5%&lt;br /&gt;
Associations | Accessors | Validators = 20%&lt;br /&gt;
Associations | Validators | Accessors = 45%&lt;br /&gt;
Validators | Accessors | Associations = 5%&lt;br /&gt;
Validators | Associations | Accessors = 0%</description>
      <pubDate>May 15, 2009 02:19</pubDate>
      <link>/posts/model-component-ordering</link>
      <guid>/posts/model-component-ordering</guid>
    </item>
    <item>
      <title>Childcare at Windy City Rails</title>
      <description>I was fortunate to run into &lt;a href=&quot;http://twitter.com/rayhightower&quot;&gt;Ray Hightower&lt;/a&gt; as we both left the &lt;span class=&quot;caps&quot;&gt;TDD&lt;/span&gt; BoF at 10PM one night. I was pretty wiped out by that point, but was still excited to find out that I was talking to the man behind &lt;a href=&quot;http://www.windycityrails.org/&quot; title=&quot;&amp;lt;span class=&amp;quot;caps&amp;quot;&amp;gt;WCR&amp;lt;/span&amp;gt;&quot;&gt;Windy City Rails&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
We had a great discussion on our way to the elevators, about conferences and how to get more women in attendance at them. I mentioned one thing that had come out in the Women in Rails panel as a suggestion: childcare at events. I am of the opinion that having childcare available at conferences, workshops, and other events will be a huge win for families in general, and perhaps women in particular. Ray was very enthusiastic about the idea, and actually followed through on researching childcare alternatives for &lt;span class=&quot;caps&quot;&gt;WCR&lt;/span&gt;!&lt;br /&gt;
&lt;br /&gt;
The Westin &amp;#8211; which is hosting the conference in September &amp;#8211; partners with two childcare centers! Now, it&amp;#8217;s not inexpensive, but what &lt;em&gt;is&lt;/em&gt; when it comes to conferences? Here is the information Ray gave me:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;American Child Care  312-644-7300&lt;br /&gt;
18.50/hr 4 hour minimum&lt;br /&gt;
20.00 agency fee&lt;br /&gt;
75.00 cancellation fee if cxl&#8217;d within 24 hrs&lt;br /&gt;
&lt;br /&gt;
American Registry  312-475-1515&lt;br /&gt;
11.50/hr 4 hour minimum (new recession price- was 18.50/hr)&lt;br /&gt;
30.00 agency fee&lt;br /&gt;
10.00 transportation fee after 10pm&lt;br /&gt;
Cash only.&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
I am so thrilled that Ray took a simple suggestion for making conferences easier on families and actually followed through on it. He didn&amp;#8217;t hide behind the usual excuses of &amp;#8220;too hard&amp;#8221;, &amp;#8220;unproven&amp;#8221;, and &amp;#8220;not my problem&amp;#8221; and he is to be commended for it.</description>
      <pubDate>May 12, 2009 20:55</pubDate>
      <link>/posts/childcare-at-windy-city-rails</link>
      <guid>/posts/childcare-at-windy-city-rails</guid>
    </item>
    <item>
      <title>Honor the Beginner</title>
      <description>I am a martial artist, and try to train either body or mind every day.&lt;br /&gt;
&lt;br /&gt;
Today I was reading a page from &lt;a href=&quot;http://www.amazon.com/gp/product/1569243085?ie=UTF8&amp;amp;tag=sterlingrosedesign-20&amp;amp;linkCode=as2&amp;amp;camp=1789&amp;amp;creative=9325&amp;amp;creativeASIN=1569243085&quot;&gt;Bow to Life: 365 Secrets From the Martial Arts for Daily Life&lt;/a&gt; and the lesson really struck home for me in terms of my work with &lt;a href=&quot;http://railsbridge.org&quot;&gt;RailsBridge&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;(Beginners are) your opportunity to participate and bring more goodness into life. Beginners let you empty your cup while filling theirs. They are life&amp;#8217;s way of vaulting you to higher consciousness and better living.&lt;br /&gt;
&amp;#8230;&lt;br /&gt;
Look for opportunities to share your expertise with others. Treat each opportunity as a learning experience for yourself. Ask yourself why life has sent you this particular person at this special time. What aspect of sharing your expertise is connected to your own current needs?&lt;/blockquote&gt;</description>
      <pubDate>May 11, 2009 16:06</pubDate>
      <link>/posts/honor-the-beginner</link>
      <guid>/posts/honor-the-beginner</guid>
    </item>
    <item>
      <title>Perpetual Footer</title>
      <description>I was spinning up a brand new client website that would (like most websites) include a copyright footer. I wanted to make sure I wouldn&amp;#8217;t have to come back year after year and update the year span, so here is what I used:&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;&lt;code&gt;&amp;amp;copy; 2009&amp;lt;%= &quot;-#{Date.today.year}&quot; if Date.today.year != 2009 %&amp;gt; ABC Company&lt;/code&gt;&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
It will display only 2009 as the copyright year until January 1, 2010, then it will start displaying a span (from 2009 through the current year). Simple.&lt;br /&gt;
&lt;br /&gt;
&lt;span class=&quot;quiet&quot;&gt;Uses Rails 2.3.2&lt;/span&gt;</description>
      <pubDate>May 10, 2009 21:39</pubDate>
      <link>/posts/perpetual-footer</link>
      <guid>/posts/perpetual-footer</guid>
    </item>
    <item>
      <title>Being More Visible</title>
      <description>RailsConf was inspiring on so many levels, it would be almost impossible to try to cram it all into one blog entry, so I won&amp;#8217;t even try. So for this entry, I want to talk about what I took away from the event in terms of being a female developer in an industry that is overwhelmingly male in its constituency.&lt;br /&gt;
&lt;br /&gt;
Before about three weeks ago, I didn&amp;#8217;t really think about it much. I was a &amp;#8220;coder who was female&amp;#8221;, not a &amp;#8220;female coder.&amp;#8221; The &amp;#8220;girl&amp;#8221; part was at best incidental. I mean, sure, I knew that I was in the minority in the #rubyonrails &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; channel, but it was a non-issue for the most part. Now, I&amp;#8217;m more conscious.&lt;br /&gt;
&lt;br /&gt;
There were about 40 female and about 1100 male attendees at RailsConf 09. That&amp;#8217;s a ratio of about 3.6%. I saw and heard (via the #railsconf &lt;span class=&quot;caps&quot;&gt;IRC&lt;/span&gt; channel) plenty of guys call it a &amp;#8220;sausage-fest.&amp;#8221; And it was. Now I&amp;#8217;m not about to sit here and say that it was anyone&amp;#8217;s fault, because the blame does not lie in any one person or any one place. The problem is endemic to the development industry, and particularly endemic to the Rails segment of that industry. The causes are numerous and include some things that are well outside the scope of things I can even hope to change.&lt;br /&gt;
&lt;br /&gt;
But just because I can&amp;#8217;t change &lt;em&gt;everything&lt;/em&gt; doesn&amp;#8217;t mean I can&amp;#8217;t change &lt;em&gt;anything&lt;/em&gt;. I can light my own &lt;a href=&quot;http://groups.google.com/group/railsbridge/browse_thread/thread/86387c9fb4304cf0/3126a55365a30079?lnk=gst&amp;amp;q=candle#3126a55365a30079&quot;&gt;candle in the darkness&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
One of the main things I took away from the &lt;a href=&quot;http://en.oreilly.com/rails2009/public/schedule/detail/8772&quot;&gt;Women in Rails&lt;/a&gt; panel was that the women who &lt;em&gt;are&lt;/em&gt; in this industry need to be more visible. Whether we&amp;#8217;re comfortable with it or not, we are potential role models to women looking at entering this field. I have been lax about posting to my blog and stepping out on other limbs, and it&amp;#8217;s time to push past that hesitance.&lt;br /&gt;
&lt;br /&gt;
So my goals as of now include:&lt;br /&gt;
&lt;br /&gt;
1) Spend at least 5 hours a week (one hour per weekday) on professional development, either reading books about Ruby/Rails development, going through tutorials, contributing to (or publishing my own) gems or plugins, experimenting with practice applications, etc.&lt;br /&gt;
2) Blog at least three times per week on something related to RoR development.&lt;br /&gt;
3) Work on &lt;a href=&quot;http://railsbridge.org&quot;&gt;RailsBridge&lt;/a&gt; or &lt;a href=&quot;http://railstutor.com&quot;&gt;Rails Tutor&lt;/a&gt; at least ten hours per week.&lt;br /&gt;
4) Get back to reading the &lt;a href=&quot;http://railsforum.com&quot;&gt;Rails Forum&lt;/a&gt; more carefully (as opposed to just looking for messages that are spam and need moderating) and offer answers where I can.&lt;br /&gt;
5) Pay more attention (when time allows) to what&amp;#8217;s going on in the #rubyonrails channel and contribute where able. Most of my &lt;a href=&quot;http://workingwithrails.com/person/15162-dana-jones&quot;&gt;Working With Rails&lt;/a&gt; recommendations (which, at 11, are admittedly few, but growing!) came from people who I helped in that channel.&lt;br /&gt;
6) Moderate at least a Birds of a Feather session at RailsConf, and maybe even submit a presentation proposal.&lt;br /&gt;
7) Attend at least one other conference this year.&lt;br /&gt;
&lt;br /&gt;
Now, that&amp;#8217;s a lot. I have four children that I homeschool, as well as other interests and activities. I still have clients I need to satisfy and a home to help take care of. But I&amp;#8217;m committed to doing it because I believe that in the long run it will be good for my career, and hopefully good for the community as well.</description>
      <pubDate>May 09, 2009 16:46</pubDate>
      <link>/posts/being-more-visible</link>
      <guid>/posts/being-more-visible</guid>
    </item>
    <item>
      <title>Practical Tips for Attending a Rails Conference</title>
      <description>I just finished attending my first-ever &lt;a href=&quot;http://www.railsconf.com&quot;&gt;RailsConf&lt;/a&gt; in Las Vegas, NV. It was an amazing experience that I&amp;#8217;ll be blogging about a lot over the next coming days. I wanted to make my first post on the subject be a (long &amp;#8211; sorry) list of tips and advice in case you ever plan to attend a similar event yourself. If you have tips of your own that you&amp;#8217;d like to share please feel free to drop them in the comments section!&lt;br /&gt;
&lt;ol&gt;&lt;li&gt;&lt;ins&gt;Bring lots of business cards.&lt;/ins&gt; One of the greatest benefits of attending a conference of any type is the contacts you will make, and it&amp;#8217;s easier for them to remember who you are and keep in touch if they have your contact information.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Take care of your feet.&lt;/ins&gt; There is a lot of walking and standing, and the days are quite long. Wear very comfortable, well-padded shoes. Put your feet up when you can. If you can find a place to &lt;em&gt;unobtrusively&lt;/em&gt; take your shoes off for a few minutes and stretch your toes, do! There aren&amp;#8217;t many people who will think badly of you for doing so, and I say screw the ones who will!&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Drink up!&lt;/ins&gt; Finish your drinks before you try to get through airport security, as they won&amp;#8217;t let you bring them through. I got stopped for a bag search on the way back home because I had a water bottle in my bag.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Don&amp;#8217;t count on the conference food.&lt;/ins&gt; It&amp;#8217;s really luck of the draw as to what you will be served. We had nothing but bagels and cream cheese served every morning for breakfast, and box lunches for every midday meal. It got monotonous and boring and wasn&amp;#8217;t all that great even on the first day. The snacks were actually much much better!&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Be prepared for sessions.&lt;/ins&gt; Do as much advance reading about the tutorials and sessions you want to attend as you can. The presenters are trying to give out a lot of information in a relatively short amount of time, and the more you know about the topic when you walk in the door, the more you will get out of the time you spend there.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Don&amp;#8217;t be shy&lt;/ins&gt; &amp;#8211; talk to people! I know that it can be intimidating to just walk up to someone and introduce yourself, but that&amp;#8217;s exactly what you need to do. Give your name; they&amp;#8217;ll give theirs back. Ask where they&amp;#8217;re from, who they work for, what they&amp;#8217;re working on. You&amp;#8217;ll be surprised at the connections you make. Maybe they work on an application that will fill a need you have on your own projects. Perhaps they&amp;#8217;re in a similar field to yours and there are networking opportunities you can take advantage of. If you don&amp;#8217;t ask, you won&amp;#8217;t know where the happy overlaps are.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Treasure your downtime.&lt;/ins&gt; Conferences are work &amp;#8211; make no mistake about it. Between focusing on learning, working on code samples, meeting and greeting, socializing, and all of the other things that take place at a conference, you &lt;em&gt;will&lt;/em&gt; wear out. I talked to a whole lot of people at RailsConf 09 and every one of them that I asked admitted to overwhelming fatigue at the end of the day. Take time to recharge quietly when and where you can &amp;#8211; just listen to your own body and it will tell you when enough is enough.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;You don&amp;#8217;t have to attend everything.&lt;/ins&gt; In a typical day, there were sessions that started at about 9am and ended at about 5pm. In addition, there were &amp;#8220;Birds of a Feather&amp;#8221; (or &amp;#8220;BoF&amp;#8221;) sessions that could extend well into the night. (I know of at least one that &lt;em&gt;started&lt;/em&gt; at 10PM!) If you try to be everywhere, you&amp;#8217;ll go nuts. Scour the schedule carefully and pick out those presentations you think you could get the most direct benefit from (whether in terms of education or networking or something else) and focus your attention on them.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Go to the keynotes.&lt;/ins&gt; I missed several, including one that was reportedly horrible and one that was reportedly amazing, and I will always regret it. If it sucks, you can always leave, or you can stay and share in the collective battle scar.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Try to sit on the aisle where you can.&lt;/ins&gt; Not only does this give you more room to spread out, it makes getting up and leaving or going to get some water a lot easier. In the case of RailsConf 09, it also meant you were more likely to have access to a power strip!&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Stay hydrated.&lt;/ins&gt; It&amp;#8217;s easy to forget, when you&amp;#8217;re so focused on the official events, but drink, a lot. Otherwise, you could get dehydrated, which leads to headaches and general grumpiness. And nobody needs to see that. :) Failing that&amp;#8230;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Bring Tylenol.&lt;/ins&gt; Get a little travel bottle of Tylenol or Advil and toss it in your bag or keep it in your pocket. Trust me on this one. Wouldn&amp;#8217;t hurt to have a tube of Chapstick and a bottle of Visine handy, either.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Take pictures.&lt;/ins&gt; Lots and lots of pictures. Nuff said.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Don&amp;#8217;t be afraid to re-ask details of someone you&amp;#8217;ve already met.&lt;/ins&gt; They probably don&amp;#8217;t remember who you are or where you live or what you do, either, so they aren&amp;#8217;t likely to be offended by a polite, &amp;#8220;I know you already told me, so I&#8217;m sorry, but what was your name again?&amp;#8221;&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Be polite.&lt;/ins&gt; Courtesy goes a really long way. Don&amp;#8217;t cut in front of someone in lines (yes, it happened to me once). Don&amp;#8217;t be loud and rude. Offer to plug and unplug power cords if you&amp;#8217;re the lucky stiff near the power strip. Take your own trash to a receptacle (don&amp;#8217;t be a pig-person). Try to be a part of leaving the conference organizers with an overall positive impression of the attendees.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Be prepared for things to go over your head.&lt;/ins&gt; Most of the people that I talked to admitted to not understanding all of what a presenter was driving at. That&amp;#8217;s ok. Take what you can from the discussion, and bully the rest.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Don&amp;#8217;t try to make a work trip into a pleasure trip.&lt;/ins&gt; Sure, you will probably have opportunities to go out on the town with other attendees (especially if you were conscientious about sticking your neck out and introducing yourself), but you should not make the mistake I did of thinking that you will have time to truly hang out with non-attendees at night. Schedule a separate trip for that or you will feel you are shortchanging yourself and others.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Plug in and charge up at every available opportunity.&lt;/ins&gt; You never know when you will have to go hours (yeah, plural) with no power at all. Obviously, this implies that you should remember to bring power cords!&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Tweet your impressions as you go along.&lt;/ins&gt; Whether you think they&amp;#8217;re important or not, people want to know what you&amp;#8217;re experiencing. Other people at the conference might want to know if a session was worthwhile or not (bonus for tweeting nuggets of useful information you pick up at a session), and those who couldn&amp;#8217;t make it want a chance to gain some insight into an event that &amp;#8211; for whatever reason &amp;#8211; they couldn&amp;#8217;t attend. In the case of RailsConf, the event organizers were actually really good about monitoring the #railsconf Twitter hashtag and responding to problems they saw reported there. Well, usually. :)&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Don&amp;#8217;t plan to work on client projects while you&amp;#8217;re there.&lt;/ins&gt; Unless you ignore everything else I&#8217;ve told you about downtime and networking and attending useful sessions, you&amp;#8217;ll be way too busy to try to write client code. In five and a half days in Las Vegas, the only client work I got done was to code the views for a photo gallery. :) If you do find yourself with some time to code, grab a friend and hack on something fun and new together. You&amp;#8217;ll learn a ton and it will be a lot more interesting.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Get a laptop bag that evenly distributes the weight across your body.&lt;/ins&gt; You can do this with either a sturdy backpack, or with a bag with a long strap so you can hang it diagonally across your chest.&lt;/li&gt;&lt;br /&gt;
&lt;li&gt;&lt;ins&gt;Get into the Caboose Conference!&lt;/ins&gt; Do the open-source contribution it takes (if you haven&amp;#8217;t already) to be able to hang out in Caboose. Not only are the most-recognized people in the community in there a lot more than in the open venue, the best food and swag winds up in there. :) Plus, if you get stuck on some code you&amp;#8217;re hacking away on, I can almost guarantee there will be someone there who knows how to help you, if only you ask.&lt;/li&gt;&lt;/ol&gt;&lt;br /&gt;
&lt;br /&gt;
I hope some of this information was useful for you, and I look forward to seeing you at a conference in the future!</description>
      <pubDate>May 08, 2009 23:05</pubDate>
      <link>/posts/practical-tips-for-attending-a-rails-conference</link>
      <guid>/posts/practical-tips-for-attending-a-rails-conference</guid>
    </item>
    <item>
      <title>RailsBridge: Bringing Awesome People Together to Do Awesome Things</title>
      <description>Over the last couple of weeks, a motivated group of people took the &lt;a href=&quot;http://www.imdb.com/title/tt0358082/&quot;&gt;See a need, fill a need&lt;/a&gt; approach to development in general, and the Rails development community in particular. The needs we saw were:&lt;br /&gt;
&lt;br /&gt;
a) Make a concerted, focused effort to encourage a sort of &amp;#8220;culture of kindness,&amp;#8221;&lt;br /&gt;
b) Promote a &amp;#8220;give back&amp;#8221; mentality by developing applications in Rails for non-profit organizations,&lt;br /&gt;
c) Support greater inclusion of all kinds of minorities, and&lt;br /&gt;
d) Provide a wealth of documentation, mentorship, and instructional material to new developers.&lt;br /&gt;
&lt;br /&gt;
With those objectives in mind, we have launched &lt;a href=&quot;http://www.railsbridge.com&quot;&gt;RailsBridge&lt;/a&gt;. Our guidelines are pretty simple: &lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;* First, do no harm. Then, help where you can.&lt;br /&gt;
* Bridge the gap from aspiring developer to contributing community member, through mentoring, teaching, and writing.&lt;br /&gt;
* Reach out to individuals and groups who are underrepresented in the community.&lt;br /&gt;
* Collaborate with other groups with similar goals.&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
There are many projects already in the planning and development phase, and we want the participation of the whole Ruby on Rails community. If you would like to take part in a fresh, positive community, you will be welcomed. Contact the coordinator of any of the current programs, or suggest your own! We certainly need as many hands as possible to realize the ambitious goals we have set for ourselves.</description>
      <pubDate>May 04, 2009 13:36</pubDate>
      <link>/posts/railsbridge-bringing-awesome-people-together-to-do-awesome-things</link>
      <guid>/posts/railsbridge-bringing-awesome-people-together-to-do-awesome-things</guid>
    </item>
    <item>
      <title>Review: Timeboxed</title>
      <description>I&amp;#8217;ve been using &lt;a href=&quot;http://sterlingrosedesign.com/posts/timeboxing&quot;&gt;timeboxing&lt;/a&gt; for a little over three weeks now, off and on, and I continue to find it a very useful technique for my own working environment.&lt;br /&gt;
&lt;br /&gt;
Yesterday, I received an email from someone at &lt;a href=&quot;http://www.macmation.com/TimeBoxed&quot;&gt;Macmation&lt;/a&gt; about their product, TimeBoxed.&lt;br /&gt;
&lt;br /&gt;
&lt;blockquote&gt;TimeBoxed was designed to be extremely simple to use.&lt;br /&gt;
Each of its features has been carefully designed and configured to adhere to the core mission of this application.&lt;br /&gt;
In fact, many features were discarded because they just couldn&amp;#8217;t live up to our stringent mission requirements.&lt;br /&gt;
The result is an application that does exactly what you need, the way you need it.&lt;/blockquote&gt;&lt;br /&gt;
&lt;br /&gt;
The install went off without a hitch and took about 30 seconds after the download.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img src=&quot;http://img.skitch.com/20090418-bx6a12qa6c69btd9xt3n6ejmmi.jpg&quot; alt=&quot;TimeBoxed status bar&quot; /&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
TimeBoxed acts as a tiny little window with a status bar and a title bar. The title bar shows the total time you set, the status bar gradually fills in and changes from green to red as the time period draws to a close.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img src=&quot;http://img.skitch.com/20090418-c2gxiwtf2rgacqcanbuuts624x.jpg&quot; alt=&quot;Timeboxed visual alerts&quot; /&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
Once time has elapsed, you are alerted in any of several ways:&lt;br /&gt;
&lt;ul&gt;&lt;li&gt;Growl notification&lt;/li&gt;&lt;li&gt;Voice-synthesized message&lt;/li&gt;&lt;li&gt;Bouncing dock icon&lt;/li&gt;&lt;li&gt;Pulsing status bar window&lt;/li&gt;&lt;li&gt;Sound (bell, chime, etc.)&lt;/li&gt;&lt;/ul&gt;&lt;br /&gt;
Being a fan of the show &lt;a href=&quot;http://www.bravotv.com/top-chef&quot;&gt;Top Chef&lt;/a&gt;, I naturally set my voice message to &amp;#8220;Knives down, hands up!&amp;#8221; TimeBoxed has all kinds of synthesized voices you can choose from &amp;#8211; anything from the cheerful &amp;#8220;Princess&amp;#8221; to the really creepy &amp;#8220;Whisper.&amp;#8221; I settled on the &amp;#8220;Alex&amp;#8221; voice which, to my ear, sounds the most realistic.&lt;br /&gt;
&lt;br /&gt;
&lt;center&gt;&lt;img src=&quot;http://img.skitch.com/20090418-jsfmu35nfs5sx7uy8ka4tu3ju9.jpg&quot; alt=&quot;Timeboxed voice options&quot; /&gt;&lt;/center&gt;&lt;br /&gt;
&lt;br /&gt;
I worried that having the status bar window always on top of the screen would distract me from writing code, so I was very glad to see that there are options for both opacity and window level, but it ended up not being a problem. I moved the status bar window to the lower-left corner of my screen, and it was totally unobtrusive there.&lt;br /&gt;
&lt;br /&gt;
My one criticism of the application is that you get no numeric indication of how much time has elapsed. It&amp;#8217;s too soon to know yet whether this is a help or a hindrance for the way I timebox, but it would be nice to have the option.&lt;br /&gt;
&lt;br /&gt;
Overall, I like the application and its voice-synthesis feature will likely make it my preferred timer when I don&amp;#8217;t need to see the numeric countdown.&lt;br /&gt;
&lt;br /&gt;
&lt;a href=&quot;http://www.macmation.com/TimeBoxed&quot;&gt;Download Free Trial of TimeBoxed&lt;/a&gt;</description>
      <pubDate>April 18, 2009 01:22</pubDate>
      <link>/posts/review-timeboxed</link>
      <guid>/posts/review-timeboxed</guid>
    </item>
    <item>
      <title>Timeboxing</title>
      <description>Yesterday, I tried an experiment in time management. I am always working on at least a dozen projects (professional and personal) at a time, and was feeling as though a) I wasn&amp;#8217;t getting enough done, b) I was distracted even while working by all of the things I hadn&amp;#8217;t finished yet, and c) time just kept getting away from me. So I decided to try a little &lt;a href=&quot;http://en.wikipedia.org/wiki/Timeboxing&quot;&gt;timeboxing&lt;/a&gt;, in conjunction with &lt;a href=&quot;http://www.trackdailygoals.com&quot;&gt;#dailygoals&lt;/a&gt;.&lt;br /&gt;
&lt;br /&gt;
The basic concept was this: Via the #dailgoals &lt;a href=&quot;http://www.twitter.com&quot;&gt;Twitter&lt;/a&gt; hashtag, I define what projects I want to work on that day. I stayed away from saying I wanted to complete anything but the most insular of tasks (placing an order, for example) and left everything else open-ended. Then, I whipped out my handy-dandy timer application, &lt;a href=&quot;http://www.apimac.com/timer/&quot;&gt;Apimac timer&lt;/a&gt; (I&amp;#8217;m sure a kitchen egg timer would work just as well) and set it for 30 minutes.&lt;br /&gt;
&lt;br /&gt;
I picked a task, started the timer, and focused purely on that topic for the allotted time. OK, as purely as having four small children would allow. :) When the timer dinged, I got to a stopping point (no more than a minute or two over), posted my &amp;#8220;&lt;strong&gt;Ding!&lt;/strong&gt;&amp;#8221; tweet, and reset the timer. I switched to a different task and did it all over again. Most tasks I assigned 30-minute intervals, but for some, I went for shorter times. These were mostly things that were for fun/breaks. I even timed my nap!&lt;br /&gt;
&lt;br /&gt;
So how did it work? I must say, I was surprised. It was the best time management technique I have ever tried, in terms of it working for me. I felt productive and focused &amp;#8211; I didn&amp;#8217;t allow myself to think of other tasks, because I knew my time allotment for the task at hand was limited and I would be switching soon. I timeboxed almost my entire day, which relieved the guilt &amp;#8211; nobody can work more hours than there are in a given day! I was able to look back on my &amp;#8220;&lt;strong&gt;Ding!&lt;/strong&gt;&amp;#8221; tweets and see just how much I had accomplished, and feel proud rather than anxious. I was &amp;#8211; for once &amp;#8211; at peace.&lt;br /&gt;
&lt;br /&gt;
I had Twitter followers throughout the day ask me how it felt, and that they felt they were being productive &amp;#8220;vicariously&amp;#8221; through me. A friend on Facebook said I worked on too many projects at once to be normal. This gave me a chuckle, because yes, I do work on a lot of projects in a given day, but during a given &amp;#8220;ding-spot&amp;#8221; (a term I just made up &amp;#8211; go me!) I was entirely focused on only one task. I was able to bill a good amount of time to a client project, but I was also able to complete and deploy a major new feature on another project &amp;#8211; one that I had been putting off for weeks because I &amp;#8220;just couldn&amp;#8217;t find the time.&amp;#8221;&lt;br /&gt;
&lt;br /&gt;
So, is this the part where I try to get you to drink the timebox Koolaid? Nope. All I&amp;#8217;m saying is, this worked very well &lt;strong&gt;for me&lt;/strong&gt;. &lt;span class=&quot;caps&quot;&gt;YMMV&lt;/span&gt;. There are lots of Timeboxing approaches out there, including (as &lt;a href=&quot;http://www.twitter.com/hardbap&quot;&gt;hardbap&lt;/a&gt; pointed out) &lt;a href=&quot;http://www.pomodorotechnique.com/&quot;&gt;The Pomodoro Technique&lt;/a&gt;. I am no management or productivity guru, and I have tried this exactly one day, so I&amp;#8217;m certainly not going to stand on a pedestal and say, &amp;#8220;This is awesome! You should do it, now!&amp;#8221; But I can say that for me, it&amp;#8217;s a winning strategy, and one I will repeat as often as I can.</description>
      <pubDate>March 23, 2009 16:24</pubDate>
      <link>/posts/timeboxing</link>
      <guid>/posts/timeboxing</guid>
    </item>
    <item>
      <title>Using AJAX to Change a User's Role</title>
      <description>&lt;b&gt;Scenario:&lt;/b&gt; Client wants to display a list of users, and the role each user currently has. The user&amp;#8217;s role should be the selected option in a select box of all roles. Administrator should be able to update the user&amp;#8217;s role by simply selecting a new role from the select box for that user, without having to reload the page.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Approach:&lt;/b&gt; Each row in the user&amp;#8217;s list should have an id that uniquely identifies it as being associated with that particular user. Each select box should also have an id field associated with the user. Choosing a new role should trigger the &lt;code&gt;onchange&lt;/code&gt; event, which executes the update on the role and displays the new user&amp;#8217;s row in place, without reloading the entire user list.&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Code:&lt;/b&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;## app/views/users/index.html.erb&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;
 &amp;lt;table&amp;gt;
   &amp;lt;% @users.each do |u| %&amp;gt;
     &amp;lt;tr id='user_row_&amp;lt;%= &quot;#{u.id}&quot; %&amp;gt;'&amp;gt;
       &amp;lt;td&amp;gt;&amp;lt;%= link_to &quot;#{u.first_name} #{u.last_name}&quot;, user_path(u) %&amp;gt;&amp;lt;/td&amp;gt;
       &amp;lt;td&amp;gt;&amp;lt;%= u.username %&amp;gt;&amp;lt;/td&amp;gt;
       &amp;lt;td&amp;gt;&amp;lt;%= u.email %&amp;gt;&amp;lt;/td&amp;gt;
       &amp;lt;td&amp;gt;&amp;lt;%= select_tag &quot;user#{u.id.to_s}&quot;, options_for_user_roles(u), :onchange =&amp;gt; 
         remote_function(:url =&amp;gt; {:controller =&amp;gt; &quot;permissions&quot;, :action =&amp;gt; 
         &quot;update_one_row&quot;}, :with =&amp;gt; &quot;'user_id=' + #{u.id} + '&amp;amp;role_id=' + 
         $('user#{u.id}').value&quot;) %&amp;gt;&amp;lt;/td&amp;gt;
       &amp;lt;td&amp;gt;&amp;lt;%= link_to(image_tag('/images/edit.png'), edit_user_path(u)) %&amp;gt;&amp;lt;/td&amp;gt;
     &amp;lt;/tr&amp;gt;
   &amp;lt;% end %&amp;gt;
 &amp;lt;/table&amp;gt;
&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;## app/controllers/users_controller.rb&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;def index
  @users = User.all
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;## app/controllers/permissions_controller.rb&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;def update_one_row
  @user = User.find(params[:user_id])
  @company = @user.company
  @role = Role.find(params[:role_id])
  unless @user.has_role?(@role.rolename)
    @user.roles.clear
    @user.roles &amp;lt;&amp;lt; @role
  end
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;## app/views/permissions/update_one_row.js.erb&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;$(&quot;user_row_&amp;lt;%=@user.id%&amp;gt;&quot;).replace(&amp;lt;%=js render(:partial =&amp;gt; 
  &quot;/users/update_one_row&quot;) %&amp;gt;);&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;## app/views/users/_update_one_row.html.erb&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;tr &amp;lt;%= &quot;id='user_row_#{@user.id}'&quot; %&amp;gt;&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= link_to &quot;#{@user.first_name} #{@user.last_name}&quot;, user_path(@user) %&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= @user.username %&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= @user.email %&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= select_tag &quot;user#{@user.id.to_s}&quot;, options_for_user_roles(@user), :onchange =&amp;gt; 
    remote_function(:url =&amp;gt; {:controller =&amp;gt; &quot;permissions&quot;, :action =&amp;gt; &quot;update_one_row&quot;}, 
    :with =&amp;gt; &quot;'user_id=' + #{@user.id} + '&amp;amp;role_id=' + $('user{@user.id}').value&quot;) %&amp;gt;&amp;lt;/td&amp;gt;
  &amp;lt;td&amp;gt;&amp;lt;%= link_to(image_tag('/images/edit.png'), edit_user_path(@user)) %&amp;gt;&amp;lt;/td&amp;gt;
&amp;lt;/tr&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;code&gt;## app/helpers/permissions_helper.rb&lt;/code&gt;&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;def options_for_user_roles(user)
  ## exclude &quot;administrator&quot; from the roles you can
  ## assign to a user
  @roles = Role.find(:all) - [Role.find_by_rolename('administrator')]
  options = &quot;&quot;
  @roles.each do |role|
    if user.roles.include?(role)
      options += &quot;&amp;lt;option id='#{role.id}' selected='selected' 
        value='#{role.id}'&amp;gt;#{role.rolename}&amp;lt;/option&amp;gt;&quot;
    else
      options += &quot;&amp;lt;option id='#{role.id}' value='#{role.id}'&amp;gt;#{role.rolename}&amp;lt;/option&amp;gt;&quot;
    end
  end
  options
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
&lt;b&gt;Additional Notes:&lt;/b&gt; In the first code snippet above (the index view) you want a fully-closed table tag. Textile isn&amp;#8217;t playing nice with that particular tag at the moment, so &amp;#8211; apologies. :) &lt;em&gt;Update:&lt;/em&gt; All fixed now. :)</description>
      <pubDate>February 09, 2009 17:26</pubDate>
      <link>/posts/using-ajax-to-change-a-users-role</link>
      <guid>/posts/using-ajax-to-change-a-users-role</guid>
    </item>
    <item>
      <title>eWeek Covers Rails 2.3 RC 1</title>
      <description>&lt;a href=&quot;http://www.eweek.com/cp/bio/Darryl-K.-Taft/&quot;&gt;Darryl K. Taft&lt;/a&gt; of &lt;a href=&quot;http://www.eweek.com&quot;&gt;eWeek&lt;/a&gt; asked several of us who tweet about Rails what we thought about yesterday&amp;#8217;s release of Rails 2.3 Release Candidate 1. &lt;a href=&quot;http://www.eweek.com/c/a/Application-Development/Developers-Warm-to-New-Ruby-on-Rails-23-Update/&quot;&gt;Here is the article&lt;/a&gt;, along with my own thoughts.</description>
      <pubDate>February 02, 2009 22:39</pubDate>
      <link>/posts/eweek-covers-rails-2-dot-3-rc-1</link>
      <guid>/posts/eweek-covers-rails-2-dot-3-rc-1</guid>
    </item>
    <item>
      <title>Rendering datetime in a user's timezone</title>
      <description>We recently had a client who wanted to account for a user&amp;#8217;s time zone when they entered dates for various fields. For example, if a user were to input a new bill, the bill entry date should default to the current date. &lt;code&gt;Time.now&lt;/code&gt; is what we had been using, but that would only give the right date if you were on the correct side of the magic &lt;span class=&quot;caps&quot;&gt;UTC&lt;/span&gt; dividing line. &lt;br /&gt;
&lt;br /&gt;
The solution to this problem involved 1) storing a user&amp;#8217;s time zone in a string field in the User model, and 2) adjusting &lt;code&gt;Time.now&lt;/code&gt; for that time zone.&lt;br /&gt;
&lt;br /&gt;
For part 1, we used Rails&amp;#8217; built-in &lt;code&gt;time_zone_select&lt;/code&gt; method:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;&amp;lt;%= form.label :time_zone, &quot;Time Zone&quot; %&amp;gt;
&amp;lt;%= time_zone_select :time_zone, @user.time_zone, nil, :default =&amp;gt; 
  &quot;Pacific Time (US &amp;amp; Canada)&quot; %&amp;gt;&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
For part 2, the solution was to add a method to the User model to get the user&amp;#8217;s current date:&lt;br /&gt;
&lt;br /&gt;
&lt;pre&gt;&lt;code&gt;def my_date(input=Time.now)
  Time.zone = time_zone
  d = input.to_datetime
  user_time_zone_date = Time.zone.utc_to_local(d)
  user_time_zone_date
end&lt;/code&gt;&lt;/pre&gt;&lt;br /&gt;
&lt;br /&gt;
This leaves the door open for you to pass in any time at all, and have it parsed for the user&amp;#8217;s current date.&lt;br /&gt;
</description>
      <pubDate>January 13, 2009 21:46</pubDate>
      <link>/posts/rendering-datetime-in-a-users-timezone</link>
      <guid>/posts/rendering-datetime-in-a-users-timezone</guid>
    </item>
    <item>
      <title>Does the world really need another Rails blog?</title>
      <description>After a few weeks of coding it, I&amp;#8217;ve finally kicked off my first purely &amp;#8220;professional&amp;#8221; weblog. I&amp;#8217;ve been coding in Ruby on Rails for a little over a year now, and decided it was about time for me to start sharing some of the things I&amp;#8217;ve learned and discovered and figured out.&lt;br /&gt;
&lt;br /&gt;
This is not a news/announcements aggregation site. There are plenty of those out there, doing it much better than I have the time for. &lt;br /&gt;
&lt;br /&gt;
So what are you likely to see here? Code snippets, tutorials (probably starting with a series on how to build a blog just like this one), obscure &lt;span class=&quot;caps&quot;&gt;API&lt;/span&gt; documentation, mentions of plugins I&amp;#8217;ve found useful or cool, etc. I plan to focus on some of the most commonly-used web functionality, with focus on doing things &amp;#8220;the Rails Way&amp;#8221; as much as possible.</description>
      <pubDate>January 05, 2009 16:28</pubDate>
      <link>/posts/does-the-world-really-need-another-rails-blog</link>
      <guid>/posts/does-the-world-really-need-another-rails-blog</guid>
    </item>
  </channel>
</rss>
