The Gift Hat blog

August 9th, 2006

I moved the main GiftHat discussion over to the shiny new Gift Hat Blog. So, if you’d like to stay up to date, please stop by.

A new Gift Hat release

August 3rd, 2006

I just snuck out another GiftHat.com release which includes two great new features:

  • You can publish your wishlist right on your website or blog. See My Wishlist on the right as an example.
  • I added a new feature to make it easy to select an image for your gift. Just type in a website for your gift and I will fetch all the images from that page and let you select one to go with your gift:

Also, pretty soon I will be adding a blog to the Gift Hat so I can move the majority of these types of announcements over there.

I am going to try to keep this blog more focused on web development using RubyOnRails and javascript, but I will include lots of examples from my projects. If you would like to know how I did any of the features in the GiftHat.com, just drop me a note and I will add it to my list of topics to discuss here.

NOTE: This blog is no longer running Typo

In this article I am going to discuss the steps necessary to add the excellent CodeRay syntax
highlighting library to your Typo blog installation. The newest version of Typo ships with
support for the syntax gem, but I have found that the
CodeRay gem does a much better job and supports a lot more languages including:

  • ruby
  • C
  • Delphi
  • HTML
  • RHTML
  • Nitro-XHTML

Install CodeRay

There are a couple different ways you can install CodeRay:

  • By gem
  • In the typo/vendor directory.

For my case, I chose to install CodeRay using the vendor directory since the gem way
is not ideal for a shared hosting environment.

To install CodeRay into your typo/vendor directory:

# Either download the CodeRay source into your typo/vendor/coderay directory or setup
an svn:externals for CodeRay. To setup the svn:externals, type this from the root
of your typo install:

svn propedit svn:externals vendor

and add this line into the externals for the vendor directory:

coderay svn://rubyforge.org/var/svn/coderay/trunk/coderay/trunk/lib

and then update your CodeRay src with this command:

svn up vendor

Create the CodeRay text filter

Now we will create a custom Typo text filter for sending code through CodeRay.

NOTE: This requires either Typo 4 or greater, or an earlier unreleased Typo that supports
text filters.

If you want to skip the explanation, here is a patch file
that you can apply from the root of your typo installation:

patch < typo.coderay.diff

This diff contains the following four changes:

  • A modification to the typo environment
  • A CodeRay text filter
  • A CodeRay css stylesheet
  • A modification to the add the CodeRay stylesheet to the typo theme

A modification to the typo environment

In order to have typo load the CodeRay code into our rails environment, we needed to add
the vendor/coderay path into the config load paths. The patch will do this for you.

A CodeRay text filter

The CodeRay text filter is very similar to the Code text filter. It is impressive how
little code it takes to add this CodeRay functionality into typo. All of the work for this
text filter is done in this method:

def self.macrofilter(controller,content,attrib,params,text='')
  lang = attrib['lang'] || 'ruby'
  tokens = CodeRay.scan(text, lang)
  result = tokens.div(:line_numbers => :table)
  '<notextile>#{result}</notextile>'
end

A CodeRay css stylesheet

After applying the patch, the CodeRay css file will be located here:

public/stylesheets/coderay.css

A modification to the add the CodeRay stylesheet to the typo theme

The patch above will apply the CodeRay css to the default azure theme. You can manually
add it to any theme by just adding this line to the top of your theme within the tags:

<%= stylesheet_link_tag "/stylesheets/coderay", :media => ‘all’ %>

Using the CodeRay text filter

To use the CodeRay text filter in your code, surround any code you wish to display in
typo:coderay tags and optionally specify the language to format (the default is ruby).
Here is a simple example (Note: remove the space between typo and coderay, I only added it so it would not be grabbed by the coderay text filter):

  <typo: coderay lang="html">
    <div id="somediv">The div that I am</div>
  </typo: coderay>

In this article, I am going to walk you through a simple technique for resizing images on the server in your Ruby On Rails app using MiniMagick. I have previously written about a technique for resizing images using javascript on the client, but I prefer the server method when possible.

MiniMagick is a ruby gem/plugin that is a wrapper around a great ruby image library called ImageMagick. There is also another well known library called RMagick that wraps ImageMagick that includes a lot more features. I chose MiniMagick for my case since I am on a shared host and the memory footprint is much smaller for MiniMagick since it basically just wraps the ImageMagick command line utilities.

Prerequisites

So, before we get started, make sure you have ImageMagick installed on your machine.

MiniMagick comes as both a gem and a plugin. Choose the one that makes sense for your project and install it. In my case, I chose the plugin since I wanted to keep MiniMagick checked in with my code in subversion.

To install the MiniMagick plugin, just download the plugin zip and extract it into your vendor/plugins directory. Please read up on the NOTES at the bottom of this article before you go for a few bugs I found with the plugin and how to fix them.

Usage

In my case, I decided to create a separate Image model for managing my images. In my Image model, I added this resize method:

def self.resize(path)
  image = MiniMagick::Image.new(path)
  w, h = image['%w %h'].split
  w = w.to_f
  h = h.to_f
  @@max_size = 100
  if (w > @@max_size || h > @@max_size)
    if (w > h)
      h = (h*(@@max_size/w)).to_i
      w = @@max_size
    else
      w = (w*(@@max_size/h)).to_i
      h = @@max_size
    end
    image.thumbnail "#{w}x#{h}"
  end
end

Now, let’s break down some of the more interesting parts:

image = MiniMagick::Image.new(path)

The above line is used to create a new MiniMagick Image object. By using the new method, I will be manipulating the actual image file on disk rather than working on a copy. If you wanted to work on a copy without modifying the original image you could the MiniMagick::Image.from_file(path) instead. When working on a copy, you would also have to use the MiniMagick::Image.write(path) method to save your image after the manipulations.

w, h = image['%w %h'].split

This line is used to grab the image width and height. The array ([]) syntax of the MiniMagick::Image class is really just a wrapper around the identify utility in ImageMagick. For a full list of options, refer to this documentation.

The remainder of that method up until the line below is just an algorithm for resizing the image to no larger than 100px on its largest side. It maintains the aspect ratio as well.

image.thumbnail "#{w}x#{h}"

The line is used to actually resize the image based on our new computed width and height. The MiniMagick::Image library exposes all of the options provided by the ImageMagick mogrify utility. For a full list of options for mogrify refer to this documentation. If you chose to create your image using the MiniMagick::Image.from_file(path) method, here is where you would write your image back to disk.

And that’s it! You should be happily resizing images using MiniMagick in no time.

NOTES: At the time of this posting, the MiniMagick plugin had a few bugs, which I have logged:

  1. In the init.rb, change this line:
    require 'mini-magic'
    

    to:

    require 'mini_magic'
    
  2. If you are using the MiniMagick::Image.write method, you will need to add the “rb” (read binary) option to the open statement within it. The final write method should read as follows:
    def write(output_path)
      open(output_path, "wb") do |output_file|
        open(@path, "rb") do |image_file|
          output_file.write(image_file.read)
        end
      end
    end
    

A New Gift Hat Release

July 17th, 2006

I just released a new version of the GiftHat.com.

This release includes a ton of new things including:

  • A total redesign of the look and feel
  • An all new friends feature for linking up with your friends at the GiftHat.com
  • Improved gift browsing including popular and recent gifts
  • Improved tagging support including tag lists and tag clouds
  • Support for username based Gift Hat URLs, such as:
    http://gifthat.com/atomgiant
  • An improved bookmarklet to pave the way for better Gift Hat bookmarks in the future.
  • Locally stored gift thumbnails.
  • Stop by and check it out if you have a few minutes.

If you ever need to count your Rails records based on a distinct column, here is a simple solution:

Gift.count_by_sql("select count(distinct url) from gifts")

In this example, I am counting the number of distinct gift urls from my gifts table.

It has been rather quiet around here as I have been rather busy lately trying to get the next release of the GiftHat.com out the door.

In the meantime, here is a simple technique I like to use to focus a form on a web page using Prototype’s built in Events:

The solution

For those of you who just want to dive right in, here is the solution:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en">
<head>
  <script src="/javascripts/prototype.js" type="text/javascript"></script>
</head>
<body>

    <script type="text/javascript">
//<![CDATA[
Event.observe(window, 'load', function() {$('focus').focus()}, false);
//]]>
</script>
<form action="/login" method="post" name="loginForm">
  <label for="username">Username</label><br/>
  <input id="focus" name="user[username]" size="30" tabindex="1" type="text" />
  <label for="username">Username</label><br/>
  <input name="user[password]" size="30" tabindex="1" type="password" />
  <input name="commit" tabindex="3" type="submit" value="Submit" />
</form>
</body>

</html>

The explaination

This line requires the prototype library:

<script src="/javascripts/prototype.js" type="text/javascript"></script>

The Event.observe javascript is where the magic happens:

<script type="text/javascript">
//<![CDATA[
Event.observe(window, 'load', function() {$('focus').focus()}, false);
//]]>
</script>

This will setup an event that will cause our dynamic function to be called when the window loads. This function will lookup an element that has an ID called focus and call its focus() method.
In case you are wondering what the CDATA part is for, that will just make sure this webpage still validates.

The last part of this is to create an element that has an ID of focus which will get the browser focus after the window loads. In the example above, it is this form element that gets the focus:

<input id="focus" name="user[username]" size="30" tabindex="1" type="text" />

You can definitely do a lot more interesting things with Prototype events than this example, but this should help get the ball rolling.

RI For Your Ruby Gems

June 23rd, 2006

Ruby comes with a great utilty called RI for searching and displaying ruby documentation. I have had varying levels of success in getting this to work with ruby gems so I wanted to share my findings so others may benefit from my trials and errors.

Attempt 1

The first tip I found for this (thanks to Brandt Lofton on the RadRails mailing list) involves modifying your site_ruby/1.8/rubygems/doc_manager.rb by changing this line

r.document(['--quiet', '--op', rdoc_dir]
+ @rdoc_args.flatten + source_dirs)

To:

r.document(['--quiet', '--op', '--merge', '-r', '--ri-system', rdoc_dir]
+ @rdoc_args.flatten + source_dirs)

You must then run the command:

gem rdoc --all

This will install all of your installed gems rdoc documentation for use by Ri.

NOTE: In my experience, this command must complete or the documentation will not be installed properly. For instance, in InstantRails1.3a, the camping-unabridged.rb file causes problems so I renamed it to camping-unabriged.rb-renamed so it will be skipped.

Attempt 2

Some people have experienced problems (myself included) with those steps above. So, I recently tried to find an alternative approach. I found this
post
by Eric Hodel, who implemented a different patch for ruby-core.

I tried following in his footsteps, but I was not successful. However, others seem to have gotten that one to work, so you may have better luck than I did.

Attempt 3

If all else fails, they say the third time is the charm. If you can’t get either of those methods to work, there is one more thing you can do to manually install your gem documentation.

This should work for any ruby code you have. Just change directories to the root of the code you want to be able to search with Ri and run this command:

rdoc --ri-site

This will install your documentation into the share/site directory of your ruby install where Ri will be able to read it.

NOTE: I had problems trying to generate the docs for all of my ruby gems at once so you may want to just do this individually for the ones that matter the most, such as actionpack, activerecord etc.

It may seem like a lot of effort just to be able to see your gem documentation from within Ri, but from my personal experience it is completely worth it. Having the ability to instantly look up the Rails documentation has definitely flattened the learning curve for me with Rails as I instantly can see how stuff works, or what the name of that AJAX method is etc.

Enjoy!

Redirecting with Lighttpd

June 20th, 2006

I just recently changed my site to permanently redirect http://www.atomgiant.com and http://blog.atomgiant.com to just http://atomgiant.com so please make a note of it.

This will make it easier for me to track my site stats, but just as important, it will have a positive impact on search engine rankings.

There are many ways to perform this redirect such as via meta redirects, but I decided to use Lighttpd for two reasons:

  1. Lighttpd makes this really easy.
  2. The redirect is instantaneous. With meta redirects there can be a very noticeable delay.

My lighttpd redirect code is as follows:

$HTTP["host"] =~ "^(www.|blog.)" {
    url.redirect = (
        "^/(.*)" => "http://atomgiant.com/$1",
        "" => "http://atomgiant.com/",
        "/" => "http://atomgiant.com/"
    )
  }

Also, don’t forget to include mod_redirect as one of your lighttpd server.modules

References:
The redirect code was adopted from here

Free Application Icon Sets

June 12th, 2006

Looking for some free application icon sets? I had a hard time finding some good ones when I was first looking for some. Thankfully I happened across these two wonderful ones:

If you know of some good ones, let me know and I’ll add them to this list.