Tuesday, August 25, 2009

PeepNotes - my Rails Rumble 2009 entry


This past weekend I took part in Rails Rumble 2009 and help create a site called PeepNote.


If you're not familiar with Rails Rumble, I'll borrow the introduction from their web site:

The Rails Rumble is a 48 hour web application development competition. As a contestant, your team gets one weekend to design, develop, and deploy the best web property that you can, using the awesome power of Ruby and Rails.


Two of my teammates have written up nice articles on our experience, so I encourage you to read them:

Thursday, August 13, 2009

Managing Tags in Rails

In this article I'm going to document a small piece of the administration component of the Ruby Rails Review that I wrote. On Ruby Rails Review we kept a collection of interesting articles regarding Ruby on Rails, and these articles were tagged with various tags so that if you went to browse the articles you could filter them by the various tags. Of course, there's no reason to implement that whole tagging system ourselves since there are plug-ins for that. To make the articles taggable we used the acts_as_taggable_on plug-in. This article just gives a method for easily editing the tags for a given article which works much like the Blogger labeling I used when writing this article. For Ruby Rails Review, the article editor form is shown below, though I've dimmed out everything but the tagging sections: As you can see, there is a text field where you can type in tags in a comma separated list, as well a list of all currently defined tags. Selected tags are shown in blue and underlined to give a visual indication that they are selected, but all tags are clickable to either select or deselect them. As tags from the list at the bottom are selected or deselected, they are added or removed from the text field. If you enter tags in the text field they are either selected or added (or deselected if you remove a tag) from the tag list below. So, how do we do this? First, the form code looks like this:

<% form_for @article_detail, :url => { :action => "update", :id => @article_detail.article_id } do |f| %>
   ...
   <%= f.text_field :tag_list, :onchange => "updateTagList(this.value);" %>
   ...
<% end %>
<div id="tags" style="margin-top:30px;">
<% @tags.each do |tag|%>
<div class="tag<%= ' selectedTag' if @article_detail.tag_list.index(tag.name) %>" onclick="selectTag(this);"><%= tag.name %></div>
<% end %>
</div>
You'll also need a little bit of CSS added to make the selected tags stand out (added to your main.css). I happened to make them blue and underlined, but you can make them highlighted or whatever you please:
.selectedTag {
      color: #247CD4;
      text-decoration: underline;
}
Finally, add the necessary JavaScript in either your application.js or a separate JavaScript file of you choosing:
function selectTag(tagElem) {
    tagElem.toggleClassName('selectedTag');
    var selected_tags = buildTagList();
    $('article_detail_tag_list').value = selected_tags;
    $('article_detail_tag_list').focus();
};

function updateTagList(selected_tags) {
    selected_tags = selected_tags.split(',');
    var tags = $H();
    $$('.tag').each(function(tag) { 
        tags.set(tag.innerHTML, tag);
        tag.removeClassName("selectedTag");
    });
    selected_tags.each(function(tagName) {
        tagName = tagName.strip();
        var tag = tags.get(tagName);
        if (tag) {
            tag.addClassName("selectedTag");
        } else {
            $('tags').insert('<div class="tag selectedTag" onclick="selectTag(this);">'+tagName+'</div>');
        }
    });
};

function buildTagList(tag) {
    var selected_tags = [];
    $$('.selectedTag').each(function(tagElem) {
        selected_tags.push(tagElem.innerHTML);
    });
    if (tag) {
        if (selected_tags.indexOf(tag) === -1) {
            selected_tags.push(tag);
        } else {
            selected_tags = selected_tags.without(tag);
        }
    }
    selected_tags = selected_tags.join(',');
    return selected_tags;
}
That's it! Now you can easily maintain the tags on your taggable items.

Monday, August 10, 2009

RailsRumble '09

 I plan to participate in this year's Rails Rumble with team Agile Nomads on August 22nd.

Friday, February 06, 2009

Thursday, January 08, 2009

Ruby tip to handle missing records

Here's quick and simple tip to cleanly handle non-existent records in Ruby.

By default if you try to use find(id) to fetch a record from your database and the id doesn't exist you'll get a RecordNotFound error like:


>> r = Record.find(9999)
ActiveRecord::RecordNotFound: Couldn't find Record with ID=9999
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1383:in `find_one'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:1366:in `find_from_ids'
from /usr/lib/ruby/gems/1.8/gems/activerecord-2.1.1/lib/active_record/base.rb:541:in `find'
from (irb):3

You could wrap it with a begin and rescue and have the rescue clause create a new record such as:

begin
r = Record.find(id)
rescue
r = Record.new
end

Or you could simply use find_by_id which will return nil if the record is not found and re-write it as:

r = Record.find_by_id(id) || Record.new