Posts from Nuby on Rails...

How I Spent My Spring Break

I just realized that it’s been almost two months since I’ve blogged! Some saw the announcement on Twitter, but for the rest, here’s what I’ve been up to:


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

A Three Finger Salute to Git

David Letterman often asks: Is this anything? And now I ask you.

The end result?

Easy setup

Download my pre-packaged services and drop in Library/Services (local or systemwide…your choice).

Download MultiClutch and set commands for multitouch gestures that call the services.

You can try it at home!

Use ThisService to make a service that calls any shell script or even a Ruby script (start autotest, run rake, etc.).

I used a simple shell script that echoes a command to the Terminal.

#!/bin/sh
echo "git pull"

Product placement

See the PeepCode Git Screencast to learn how to use Git.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

About This Blog: Custom Textile

When I suggested that you write your own blog software, I had no idea that some people would actually take me seriously!

So here’s another tidbit to help you on your way: custom Textile tags.

The Feature

As a developer, it’s nice to use Textile or Markdown for text entry. Simple tags will be converted to HTML, which will save typing and automatically apply some typographic rules.

RedCloth 3 Logo
Figure A RedCloth 3 Logo

But it can go one step further if you’re using RedCloth. You can subclass RedCloth and add methods that define your own tags. This is a great way to add shortcuts for complicated sets of HTML or inject hooks for CSS and Javascript.

To create Figure A, I used a technique mentioned by Garrett Dimon in a Digital Web article. It involves a div enhanced with a few CSS classes, enclosing a caption and an image. In addition, I have the power to make it small, medium, or large. A more complete solution would even allow for alternate backgrounds and placement.

But that’s a lot to type every time I want to reference a captioned image! Instead, I wrote a custom Textile tag to do it for me.

Usage

Here’s the custom tag I use:

figure(med). RedCloth 3 Logo | redcloth3-title.jpg

Let’s break it down:

In that single line, I have all the information I need to construct a figure. Those 50 characters will result in over 200 characters of HTML. I can also use a few lines of Ruby to assign an auto-incrementing figure letter (“Figure A”) and reuse the caption as an alt tag for the image.

Implementation

First, choose a color for your subclass. CaneSugarBrownCloth? MintJulepGreenCloth? It could take hours.

Next, create a file for your subclass. I put yellow_cloth.rb in the lib directory and required it from environment.rb.

unless RedCloth
  require 'RedCloth'
end
class YellowCloth < RedCloth
  # ...

Next, define your custom method. I have a simple ruby tag that applies a CSS class for use with my code highlighter.

def textile_ruby( tag, atts, cite, content )
  # TODO Use the arguments to build some HTML 
  #      and return a string.
end

The arguments passed in can be reused or ignored.

The figure tag is more complicated.

def textile_figure(tag, atts, cite, content)
  span_class = "" 
  if atts =~ /class="([^\"]+)"/
    span_class = $1
  end
  (caption, img_url) = content.split("|").map { |w| w.strip! }
  figure_name = "Figure " + @figure_counter.chr
  figure_id   = figure_name.downcase.gsub(" ", "-")
  @figure_counter += 1
  # TODO Construct the HTML
end

Finally, here’s the code to setup the counter:

def initialize(*args)
  @figure_counter = ?A
  super
end

To use your new class, you can override the built-in textilize helper or write a before_save callback on your model to convert the text to HTML with your custom subclass.

before_save :textilize_body
def textilize_body
  self.body_html = YellowCloth.new(self.body).to_html
end

The entire code can be downloaded: yellow_cloth.rb

Bonus

Pipe Text
Figure B Pipe Text

If you use TextMate, you may be aware of the “Show Web Preview” menu item.

It can pipe the text of the current document through its own textile.rb script or through your custom script. I wrote a simple script that uses my subclass instead of RedCloth.

# script/textile.rb
require 'rubygems'
require 'yellow_cloth'
textile = ARGV[0] ? File.read(ARGV[0]) : STDIN.read
puts YellowCloth.new(textile).to_html

Then use the full path to this script as the argument to ‘Pipe text through’:

/Users/topfunky/repos/funkyblog/script/textile.rb

Product Placement

I’ll be speaking at both RailsConf Portland and RubyFringe.

After many requests, I’m proud to introduce the new PeepCode Unlimited plan that gives you a year of access to all PeepCode content. On sale for only $139 until March 21.

Merb is a great compliment to Rails or a capable web framework in its own right. A draft of the PeepCode PDF on Merb is now available (includes a free upgrade when the final is published in the next few weeks).

PeepCode has been growing quickly and we have a ton of new content in the works. Ryan Daigle’s Rails 2 PDF recently became the best-selling PeepCode product of all time. Cody Fauser’s ActiveMerchant PDF is already being called a must read.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Better Reporting with Sparklines

Three pens for five dollars, black, red and blue, recommended by scholars. —Buck 65

Two events from January, unrelated but relevant:

  1. I toured the offices of Highgroove Studios and viewed their upcoming Scout reporting tool. They’ve written their graphing tool to allow easy comparisons between any group of measurements on the system, such as hits to their blog vs. new signups to their webapp. Comparing seemingly unrelated datasets often results in unexpected conclusions.
  2. Information design guru Edward Tufte posted a video review of the iPhone. One of his widget-related suggestions was to include sparklines to show months of history instead of just a single number.

A third event preceding either of these was a redesign of my internal reporting page to use sparklines extensively.

The Problem

Previously, I used Gruff to generate one or two 400×300px graphs to show a few important metrics. But it kept bugging me that I had all kinds of information in the database that I couldn’t visualize.

A big, data-thin graph.
Figure A A big, data-thin graph.

I like to use a single reporting page with as much information as possible. I also want to be able to apply a different stylesheet and view these pages on my iPhone or a laptop with a small screen.

The problem with large graphs is that adding more of them means occupying a lot more space on the page. Having a bunch of large graphs makes it hard to get a quick idea of where things are at.

Books such as Information Dashboard Design observe the fact that graphs are best at showing general trends, not specific numbers. Tables are great at showing specific numbers, but not general trends. So why not omit all the labeling and just focus on the graphic?

So I scrapped all the labeled, numbered, scaled graphs and replaced them with purely graphical sparklines that each show about three months of data in 300×30px. When I need to know the exact numbers, I can look at a nearby table that lists the data for the current day or the past week.

Go Small

I started with a graph of the number of dynamic hits to the site, as reported by the Rails analyzer and stored in the database.

Two months of daily dynamic hits.
Figure B Two months of daily dynamic hits.

This isn’t very useful alone. The graph isn’t scaled from zero, so it’s impossible to make specific conclusions. But it is valuable for finding out about relative changes from day to day.

I also added a white line as a target value for comparison. Specific numbers aren’t relevant, but I can tell whether or not I’ve hit the target for the day.

Where it really starts to get interesting is when you add other values to compare to.

Three months of product releases.
Figure C Three months of product releases.

Here’s a whisker graph marking the days when products were released. Today is on the far right. You can see a few correlations between product releases and the number of hits to the site. The conclusion may be obvious (product releases result in hits to the site), but now the graph of hits makes a little more sense. A few recent traffic spikes on the right side can be explained by a corresponding product release.

Next, I added a graph of overall daily performance.

Two months of overall performance.
Figure D Two months of overall performance.

Performance is pretty steady except for some recent fluctuations. This statistic isn’t too meaningful since it goes all the way from the delivery of action cached pages to slower pages that call remote APIs.

In order to track a specific page, I added another sparkline.

Products#show action performance.
Figure E Products#show action performance.

Many more could be added: daily revenue, user signups, coupon redemptions, referrers from a specific site, downloads.

Putting these all together, I get a graph that is about half as tall as the single graph shown at the beginning, but shows several hundred numbers.

Combined
Figure F Combined

They can be stacked on a web page, viewed on an iPhone, and compared easily.

Tips

In order to make the most of stacked sparklines, I’ve found it helpful to:

To get you started, here’s some sample code.

Make a controller that will render the graphics. Include an image_tag in your view that calls the controller.

<%= image_tag(formatted_graph_url('hits_by_day_past_three_months', :format => 'png')) %>

I like to use the show action and check params[:id] for the name of a recognized report (/graphs/hits_by_day_past_three_months.png). And of course, add a before_filter to restrict access!

Most graphs will have similar options, so I wrote a method that returns a hash of default options.

def default_sparkline_options
  {
    :background_color => 'transparent',
    :step             => 3,
    :height           => 30,
    :line_color       => "#6699cc",
    :underneath_color => "#ebf3f6",
  }
end

Another method generates the graph and caches the binary result in memcached for an hour.

def hits_by_day_past_three_months
  graph = Cache.get("Sparklines:hits_by_day_past_three_months", 1.hour) {
    records = LogAnalysisRequestTime.find_recent_by_resource("All")
    data    = records.map { |r| r.quantity.to_f  }
    graph   = Sparklines.plot_to_image data, default_sparkline_options.merge({
      :target => 1_000_000
    })
    annotate(graph, "Daily Dynamic Hits")
    graph = graph.to_blob
  }
  send_data graph, :type => "image/png", :disposition => "inline" 
end

The annotate method adds a white box and label to the bottom of the sparkline, using a pixel font.

Two things confused me at first:

Resources

Recently Published at PeepCode


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Rails Podcast Road Trip to San Francisco

I’ll be in San Francisco next week (January 15-18)! I have quite a few interviews planned for the Rails Podcast and apparently there’s a computer conference going on, too.

I’m planning to be at Osha Thai, 149 2nd St (map) on Tuesday night at about 7pm. If you’re in the area, I’d love to see you there!


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Chunky Bacon: A Public Service Announcement

Fox tall and fox small
Figure A Fox tall and fox small

In the past few months, I’ve been on the receiving end of several conversations to the effect of “Why do you use the word ‘bacon’ in some of your code examples? Are you a flaming anti-vegan, or just a pork lobbyist?”

I learned Ruby from the classic Why’s Poignant Guide to Ruby. Or rather, I read The Poignant Guide cover to cover and then decided to learn Ruby.

Adrian Holovaty reviewed it by saying

I attempted to [read it] then I started sticking a pen in my eye because I was so annoyed.

Unfortunately, The Poignant Guide is required reading for ALL Ruby programmers! Remove all pens from your pockets, then read at least…

Then go back to Chapter 2 and follow it through to the end. There is also a soundtrack.

Remember, we need to keep up with other developers who are much funnier than us!

This has been a public service announcement.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

About This Blog: Beanstalk Messaging Queue

Messaging queues are a tool for executing code without taxing your web application processes.
Figure A Messaging queues are a tool for executing code without taxing your web application processes.

Web developers often get into the rut of thinking about every programming task in the context of a request and a response. A request comes for a URL, content is retrieved and converted into useful output, then sent back to the client. Lather, rinse, repeat.

But there are also other types of programming tasks that don’t fit into that cycle. What about tasks that need to happen

Here are some examples from my applications:

Previously, I approached most of these problems with a few rake tasks and a cron job that ran every minute. While it worked, it wasn’t as fast as it could be and felt a bit hackish (a delay of even one minute is too slow sometimes).

For a while, I’ve wanted to learn more about messaging queues. I love tools that don’t only enhance something I’m already doing, but completely change the way I think about designing an application.

The Problem

If one process calls a resource-intensive method, it won't be available to answer web requests.
Figure B If one process calls a resource-intensive method, it won’t be available to answer web requests.

Queues are a great tool for some tasks. Having the ability to send something off to a queue can solve some of these problems and also give you another option for optimizing the speed of normal HTTP responses, too.

Initially, I decided to try this out on my blog. I use the remote Akismet service to check comments for SPAM. To be honest, Akismet is usually fast enough that I could make the call in the middle of the request without any problems, but I wanted to try out the message queue before deploying a similar idea at PeepCode.com.

In the application, every comment starts out with a received state (using acts_as_state_machine). The Comment controller will fire off a job and a separate worker will handle the SPAM-checking so the web process can respond quickly and get back to work responding to other web requests.

Sending jobs to a queue keeps Rails processes available to do what they do best...answer web requests.
Figure C Sending jobs to a queue keeps Rails processes available to do what they do best…answer web requests.

Messaging Servers

There’s been some fresh activity even just over the last few weeks in this area. Ara Howard compared some of these recently. I haven’t evaluated all of these packages, but here are a few I’ve looked at:

Product Features Drawbacks
beanstalkd Fast, simple, designed to mirror the style of memcached. Rails plugin available, or usable with a simple Ruby-based API. Server written in C, but is very easy to install. Memory only…jobs are not persistent. New, so the internal protocol may change. Workers may be difficult to manage.
bj Rails plugin. Self-spawning. Can only send shell commands. Jobs start a full copy of your Rails app on every execution.
BackgroundRB Ruby-based. Can be polled for incremental feedback on the progress of a job. Recently rewritten.
Amazon SQS Runs on Amazon’s cluster, so it can handle a ton of traffic. Operated by Amazon, so it doesn’t run locally. Not open source.
Apache ActiveMQ Well-known. Persistent. Requires several installation steps and database tables.
ActiveMessaging Rails plugin. Works with ActiveMQ and others. Requires external job server.
BBQ Nothing to install…involves only a single line of code! Doesn’t work on Windows NT4.

For this blog, I chose to try beanstalkd.

Installation

Download the beanstalkd server and compile it. Use make for production or make debug for your development copy (to print out extra messages as it’s working). There’s no task to install it, but you can just copy the executable to /usr/local/bin.

Start the server (use -h to see other possible arguments):

% beanstalkd
beanstalkd: net.c:90 in unbrake: releasing the brakes

Install the beanstalk-client gem. For this blog, I chose to use the gem directly.

sudo gem install beanstalk-client

In merb_init.rb (or config/environment.rb), I setup a connection to the beanstalk server.

BEANSTALK = Beanstalk::Pool.new(['localhost:11300'])

In the Comments controller, I put a comment job into the queue, using the id of the new comment.

# Comments controller
def create
  @comment = Comment.new(params[:comment])
  if @comment.save
    BEANSTALK.yput({:type => "comment", :id => @comment.id}) rescue nil
    # Then redirect and return

The yput method uses YAML to serialize any arguments and put them into the queue.

Finally, I wrote a rake task to function as the worker.

loop do
  job = BEANSTALK.reserve
  # ybody deserializes the job
  job_hash = job.ybody
  case job_hash[:type]
  when "comment" 
    if Comment.check_for_spam(job_hash[:id])
      job.delete
    else
      job.bury
    end
  else
    puts "Don't know what type of job this is: #{job_hash.inspect}" 
  end
end

In the future, I’d like to look into using daemonize or some other method for running the worker. In the meantime, I’m using god to start the worker and keep it running.

The details are a bit of a hack, but here is the god.conf if you want to try it. The benefit is that god keeps the worker running and daemonizes it so it runs in the background.

sudo god start -c /var/www/apps/mysite.com/current/config/god.conf

I can also call god restart beanstalk-worker from a Capistrano task to restart it and keep the code fresh.

Results

The comments screen shows the state of comments.
Figure D The comments screen shows the state of comments.

In practice over the past week or so, this has been very reliable. The message passing is so fast that sometimes it actually runs the SPAM check before the redirect back to the article page is done!

It was fairly simple to setup and now provides me with a tool for accomplishing tasks that don’t need to be completed in the scope of an HTTP response.

Tips

Future

Now that it’s working smoothly here, I hope to use it on PeepCode. Some possibilities:

Finally, PeepCode in Italiano!

Ryan Daigle’s Rails 2 PDF is now available in Italiano as well as English and Español.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

About This Blog: Memcached

An interview at RubyInside recently suggested that Rails developers who want to be hired should maintain a Rails-related blog.

I’ll add to this and say that every beginning Rails developer should write their own blog software. It’s a great learning experience and you can try things that aren’t possible with just an app running on localhost. It’s also a great environment for learning without the pressure of a mission-critical app. When you’re working for a client and deploying an important application, you’ll have made all the beginner mistakes on your own time (hopefully).

This blog started on shared hosting with Typo software. I later switched to a VPS with 128 MB RAM and currently run on a RailsMachine VPS with 512 MB RAM.

In the process, I’ve learned a lot about

If you need a blog for your business or for a client, I would definitely check out Mephisto, Radiant, or Simplelog. But if you’re thinking about starting a blog for yourself, you should write your own from scratch. It only requires 2 controllers (Articles and Comments) and apparently some guy even filmed a screencast showing you how to start one in only 15 minutes.

Every developer’s favorite topic: Performance

A Wordpress lecture mentioned the fact that a standard Wordpress install on a given server only achieves about 8 requests per second. The way they get it up to 300 req/sec is not by profiling loops and optimizing method calls, but by caching as much as possible.

The biggest speed benefit you can get is from page caching. However, that entails writing a bunch of code to expire the cached pages when articles are edited, comments are made, or templates are changed.

Expiration by Key Name with Memcached

Recently, I decided to try out some caching strategies I had read about1. The idea is to use memcached to store objects with keys that will automatically expire when the item changes.

For example, this page you are reading needs to expire if the article is edited or if new non-SPAM comments are posted.

This page has several sections that could cause the cache to become stale.
Figure A This page has several sections that could cause the cache to become stale.

So I’m caching the entire rendered page in memcached, with the article’s ID, timestamp, and number of comments in the key. In memory, that’s something like

"Articles:show:11097:1197661574:11"
The memcached key for this page includes several values corresponding to items which will invalidate the cache.
Figure B The memcached key for this page includes several values corresponding to items which will invalidate the cache.

This way, there’s no need to explicitly delete cached items. The application will ask for a new page when the data changes, and if memcached is full it will clear out the older, unused items.

Adding a comment causes the a new key to be calculated, which prompts a new page to be generated.
Figure C Adding a comment causes the a new key to be calculated, which prompts a new page to be generated.

Implementation

NOTE: You’ll need to have a memcached server running. I wrote a previous article about how to do that.

I’m using this technique both on my blog and at PeepCode.

First, I’ve put most of the key logic into the Article model.

class Article < ActiveRecord::Base
  def cache_key
    "#{self.class.name}:#{id}:#{updated_at.to_i}:#{ham_comments.length}" 
  end

For this blog (using Merb), the controller is pretty simple since render returns the HTML that was generated.

# Articles controller
def show
  @article = Article.find params[:id]
  Cache.get("Articles:show:#{@article.cache_key}", 1.hour) do
    render
  end
end

I’ve also wrapped it in some extra logic that doesn’t use the cached version if there is a flash message to display.

For PeepCode (using Rails), I wrote a render_cached method in the ApplicationController that handles more of this automatically. It takes a key, an expiration time, and a Hash of options that will be sent to the Rails render method.

Here’s how it’s called:

render_cached(@article.cache_key, 1.hour, :action => "show")

The render_cached method does several things:

def render_cached(key, expiration, render_options)
  return unless perform_caching
  if should_cache?
    combined_key = [
      'controller',
      controller_name,
      action_name,
      params[:format] || 'html',
      key
    ].join(':')
    output = Cache.get(combined_key, expiration) do
      render_to_string render_options
    end
    render :text => output
  else
    render render_options
  end
end

The should_cache? method looks like this:

def should_cache?
  (current_user.nil? && current_order.nil? && flash[:notice].blank?)
end

Summary

Performance chart of an application using this technique (values are in requests per second).
Figure D Performance chart of an application using this technique (values are in requests per second).

Overall, this has worked quite well. The most frequently accessed pages turn out to be pretty responsive. The cached versions perform much faster and there’s not a single line of cache-expiring code.

Raw performance numbers from pl_analyze (requests per second, controller and action names omitted):

And a word from our sponsor…

I’ve got several authors working on some great PeepCode PDF books. They will be published in the next few months.

Currently, many people have found Ryan Daigle’s Rails2 PDF to be useful for getting up to speed with Rails 2.0.1. It’s even available in Español and will soon be available in a few other languages, too.

I refilmed the Capistrano 2 screencast from scratch. It’s mostly the same content as the first Capistrano screencast, but is up to date for the new namespaces, callbacks, and other features of Capistrano 2.

The Rails from Scratch series has been updated with code and notes about Rails 2.0.1 compatibility. It’s a free update if you purchased it in the past.

Finally, I published a screencast on Git a while ago. I’m using Git wherever possible and really love the speed, easy branching, and flexibility in areas that were frustrating in Subversion.

Resources

1 Articles about auto-expiring memcached keys:


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

RubyConf 2007

RubyConf 2007 was even better than last year. Unfortunately, Adam Keys couldn’t make it, so I brought a larger-than-life sized poster of him (via Wallhogs).

Several Rubyists were game to be photographed in their favorite death metal pose.

(Also on Flickr)

And finally, Wilson Bilkovich with the Kama Sutra of death metal poses.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Future of Web Apps Conference

Last week I made a spontaneous trip to the Future of Web Apps conference in London. I wasn’t planning to go, but I’m glad I did…there were many great talks and I learned a lot about the greater web development community, especially people’s impressions about Ruby on Rails.

It had the highest ratio of quality talks of any conference I’ve been to. Here are my notes from a few of the most useful talks.

Steve Souders, Yahoo, High Performance Web Sites

Yahoo’s performance expert (and recent author) talked about performance. Not a word was said about MySQL optimization or profiling your server-side code…it was all about increasing the subjective page load on the client.

As server-side web developers, we would like to think that performance is all about making SQL queries more efficient and making our Ruby code faster. The theory presented was that a user’s impression of the speed of a site depends much more on things like compressed content, placement of script include tags, and the geographic location of the content being served. He also mentioned using a content delivery network, but this is quite expensive for a small site (I’ve heard that an introductory account with Akamai starts at US$10k per month).

Over the past year or two, I’ve used some of these techniques on this blog and other sites. Rails-specific resources:

The YSlow plugin for FireBug can also help analyze a site for the issues mentioned.

Matt Mullenweg, Wordpress

Slides

The author of Wordpress talked about scaling their blog-hosting service to the point of being one of the top 25 most visited sites on the net.

Notable points:

Interestingly, Matt answered a question about client-side optimization and felt that a content delivery network advocated by Steve Souders was not worth the work. They serve Wordpress.com assets from three servers in Texas, and also from Amazon S3.

Matt Biddulph, Dopplr

Slides

Matt Biddulph gave a useful talk on implementing Dopplr. A few interesting points:

On another note, I was surprised to see S3 download speeds in excess of 250kb/second from London. I thought they would limit the speed at which files are served, but apparently that’s not the case. Even so, I’ve bought a small VPS in Australia and am nearly ready to launch a Merb-based asset server for serving PeepCode downloads to Australia and Asia.

You Are P.R.

On the Rails front, it was shocking to hear that Yahoo is using Rails for their code-named “FireEagle” geotracking service after their commitment to use PHP for everything. Maybe it’s just for the prototype? It’s sure to get a ton of traffic when it launches.

The most frequent Rails-related comment I heard from people at the conference was about Derek Silvers’ post on Why I Switched back to PHP. Most people probably read the title, concluded that Rails wasn’t worth learning, and went about their business (at least that’s the content of most of the comments I heard at the conference).

I have a ton of respect for Derek and I think the article hasn’t been properly understood by most people. However, as a developer for an open source product, you are the only public relations department available. In an upcoming interview for the Rails podcast, James Cox talks about how PHP had to intentionally think about the public image of the language. They actually took steps to make sure that accurate information was being communicated instead of only the headline-worthy news.

Where will this come from for Rails? The author of Rails is unlikely to become a calm, diplomatic advocate in a way that non-Ruby web developers can appreciate. Heck, even the Seattle.rb has a reputation for promoting their projects in an offensive way. For the core team, it may not matter whether or not Rails is widely adopted, but for those of us who make a daily living using Rails, the public reputation of Rails IS important.

At one point there was something called MINASWAN, but I don’t think that is very well known inside the Rails community (not to mention outside of it).

So is there hope for the Rails PR machine? Is it possible for us to reverse the popular opinion of it as an unscalable, offensively-promoted niche framework?


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Dynamic CSS

Presented at RailsConf 2007 in Berlin

Rails provides many built-in mime types that you can generate in your application. Unfortunately, CSS was forgotten!

Default mime types in Rails 1.2
Figure A Default mime types in Rails 1.2

Why generate CSS dynamically?

Why would you want to generate CSS dynamically? As a programmer, it annoys me to repeat the same hex values all over my CSS documents. Even worse, I have to make notes to remind myself what colors I’m using.

Many values are repeated in CSS files.
Figure B Many values are repeated in CSS files.

Not only colors, but HTML tags themselves are repeated inside CSS documents when I need to specify a style for a child element. For example, if I want to set a style for a link inside a list item, I have to repeatedly mention the li tag.

li {
  color: blue;
}  
li a {
  color: green;
}
li a:hover {
  color: yellow;
}

Generating CSS dynamically also gives you the ability to make your web applications smarter. For example, here are two columns. Normally, your Rails application would have no way to find out how wide they are. But if you store the column widths in a database table and generate the CSS, then other parts of your application can query the database for that information.

Your application can be smarter if it knows even just a few things about your layout.
Figure C Your application can be smarter if it knows even just a few things about your layout.

I worked on a site where we used this technique. PNN gives you the option of dragging a photo between columns of a layout. When you do, the photo is dynamically resized to fit the column. You could do this by squishing the image with CSS, but instead, we sent back a photo that was perfectly sized for the column.

Smart Columns

? Short PNN Columns Screencast

But I don’t do CSS! My designer does!

CSS controls many aspects of a page’s appearance. You may want to generate only a part of the CSS, while leaving the rest to a designer. In the example above, we generated a small snippet of CSS to control the layout. The rest was accomplished with static CSS.

Making even a few elements of your CSS dynamic can open up many possibilities.
Figure D Making even a few elements of your CSS dynamic can open up many possibilities.

How? ERb

There are several plugins for working with CSS in Rails. The easiest way is to just use the ERb templates that are built into Rails already.

? Short CSS with ERb Screencast

The benefits of this approach are:

How? Sass

I use the HAML plugin for my templates and it comes with the Sass engine for generating CSS. It’s much more powerful than ERb because it was built specifically for CSS. Fortunately, most of the elements mirror standard CSS syntax, so it’s easy to learn.

SASS syntax matches the CSS you already know.
Figure E SASS syntax matches the CSS you already know.

Sass works outside of the normal Rails controller system. Put your .sass files into public/stylesheets/sass and they will be converted to CSS when your application starts up.

In production, SASS generates static CSS files once, so there's no performance hit.
Figure F In production, SASS generates static CSS files once, so there’s no performance hit.

Sass also solves the nesting problem. Just indent a declaration and it will generate the appropriate CSS for nested items (inside the menu element here).

?

The best thing about it is…variables! You can define a color once and reuse it. Variables start with an exclamation mark, and you can reuse variables by putting an equals sign in the attribute declaration.

Colors and measurements can be specified once and reused.
Figure G Colors and measurements can be specified once and reused.

And you can do math! Add or subtract colors to generate darker or lighter shades.

Math with colors and measurements is possible.
Figure H Math with colors and measurements is possible.

There are many other features in Sass. You can split your code into separate files and they will be combined into a single document for production. You can even put variable declarations in one file and reuse those variables in other files.

SASS syntax makes it easy to split variables and directives into separate files for organization.
Figure I SASS syntax makes it easy to split variables and directives into separate files for organization.

This very blog is using Sass with Merb. I wrote a Stylesheet controller that looks something like this:

London, Tuesday, October 2, 6:30pm

In other news, I’ll be in London this next week, attending the Future of Web Apps Conference.

I’m also going to be at the George Pub on Tuesday night, handing out PeepCode t-shirts! Several dozen Rubyists have already replied and will be there, too.

http://lrug.org/nights/2007/09/26/episode-4-deadly-vision/

I’ve also published the third part of the RSpec Screencast at PeepCode. The next is one on the git SCM and was edited by Git maintainer Junio C Hamano. I hope to publish it shortly after I return from London (week of October 10).


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Is Free Beer Possible?

Don’t know the words / Kids already hummin’ with it. —Buck 65

Or more accurately, “Is Free, Community-Driven Open Source Documentation Possible?”

A few times a month, I receive an email directing my attention to a new plugin repository or Rails documentation site.

They are usually beautifully designed, but painfully bereft of actual plugins or useful documentation. They are a blank wall, waiting for a kid with a spray can to supply decoration. So far, that hasn’t happened.

Why not?

The Problem

People want to help the community, and it seems that the best way is to build a site where people can contribute. The problem is that the people who need the information aren’t able to give it, and the people who have the knowledge are too busy to write it down.

A beautiful looking site is good for attracting visitors, but it isn’t necessarily good for attracting workers. Programmers don’t visit empty sites because they are nice to look at (but graphic designers do!).

What these sites need is content! They need knowledgeable people who are willing to document the finer points of Rails for the benefit of those who are learning it. So mostly, they need a way to attract experienced developers.

In many cases, the founders want to run a job board or Google ads and make a bit of cash from the traffic to their (currently empty) site. Financial motivation is not the problem. (It has worked for me, and people thank me daily for it!) The problem is how it is implemented. It’s a “business plan” that provides no sustaining benefit for those who are actually doing the work (i.e. writing the documentation).

These sites will continue to go up and stay empty unless there is a different kind of “business plan” behind them, one that provides a tangible motivation for people to come and write documentation. Documentation is often boring to write and time-consuming. People don’t do it for fun!

Solutions

Existing Sites

A Different Approach

Although there are many aggregators (Planet, Corner) and great news portals (Ruby Inside), no one has tried to organize existing blog articles. What about a system that rates posts and assembles a list of classic blog posts on various topics? (such as Jamis Buck’s classic posts)

Organize it topically, not chronologically. Treat it like a library. Use the information that people are already writing and reward them by sending traffic to their blog.

What if the proprietors could dedicate an hour or two a day toward hunting down and rating top blog posts? There is already great documentation on some topics, but it’s scattered all over the place.

Maybe the Google Ad or job board revenue could even be paid back to blog authors for writing quality posts on requested topics.

If you build it well, I would even consider buying advertising space there each month.

Your Thoughts

Why have documentation projects failed? Am I right in thinking that continuing documentation is impossible without financial backing or a self-supporting business plan of some sort?


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Massive List of Rails Development Tips

During a brief 2 years of writing Rails applications, I’ve learned many things that have become part of my normal workflow.

I recently published a draft of the first PeepCode PDF minibook. It’s called Ruby on Rails Code Review.

It currently contains 16 chapters of tips for building a solid Rails application and I thought it would be useful to briefly mention them here (I’ll be adding one or two more chapters for the final release). They are written as combinations of common mistakes and better implementations. If you like the term, you could call them “Best Practices.”

Are you doing these things in your applications? What would you add to this list?

Full Chapters

Mentioned in Passing

(Thanks to Courtenay Gasking for many of these guidelines).

Several people have written to say that they have put together blank Rails projects that include all the plugins and defaults that they use on new projects. Maybe I should put one together that uses all the suggestions you see here?

In Other News

Over a year and a half ago, I signed on to write two chapters in a book about Rails Deployment. That book is now available for pre-purchase as a Pragmatic Beta PDF!

I’ll be speaking at RailsConf in Berlin! I’m up against Twitter, JRuby, and Amazon, but I doubt any of them will be giving away random PeepCode t-shirts, PeepCode coupons, or have their own marching band.

And there are a few hours left in the PeepCode one-year anniversary sale! Buy a 10-pack and get 12 credits instead of 10!


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Automation with RStakeout

autotest is a fantastic tool. If you’re not using it, you’re missing out on a large part of the joy that life has to offer.

Ryan Davis and Eric Hodel can stop reading this article now.

For everyone else,

Customizable File Watching With rstakeout!

Mike Clark wrote a ruby implementation of a tool to watch files, then run any arbitrary command.

I modified it to look for Test::Unit or rSpec output and pop up a growl notification also. (Apparently the original author of the Mac OS X native app also did the same.)

In any case, this is a really useful tool. Autotest won’t run in Test::Unit mode if you have a spec directory, but rstakeout can be told to run any command when files change. It’s not as smart as autotest (it won’t match the command to the name of the file that changed).

Download

Get rstakeout from one of my Subversion repositories.

http://svn.topfunky.com/public/scripts/rstakeout.rb

Usage

rstakeout "command to run" 'files to watch' 'more files to watch'

It’s most useful when you can use Ruby’s file globbing instead of the shell’s. If you do something like '**/*.rb', Ruby will recurse into all subdirectories. The shell will only go down a single directory, so quote the final arguments so they will be passed to Ruby.

Examples

Rerun a single unit test when the implementation or test file is saved:

rstakeout "ruby test/unit/user_test.rb" 'app/models/user.rb' 'test/unit/user_test.rb'

Run the unit tests when model files are saved:

rstakeout "rake test:units" 'app/models/*.rb' 'test/unit/*.rb'

Run a single functional test, then run flog and filter the output with grep. This will show if your code is becoming more complicated or less.

rstakeout "ruby test/functional/orders_controller_test.rb && \
           flog -a app/controllers/orders_controller.rb | \
           grep 'OrdersController#checkout'" 'app/**/*' 'test/**/*'

Loaded suite test/functional/orders_controller_test
Started
..............................
Finished in 3.536267 seconds.

30 tests, 74 assertions, 0 failures, 0 errors
OrdersController#checkout: (56.5)
OrdersController#checkout_with_google: (17.6)
OrdersController#checkout_with_paypal: (15.9)

Lather, rise, repeat with Heckle or any other testing tool.

I’m using this to generate PDF documents using my automated system for PeepCode Press.

rstakeout "ruby script/generate code_review" '**/*.textile'

I use a shell shortcut to reuse the previous command.

$ some --long shell command
$ rstakeout "!!" 'files/**/*'

Or with autotest…

Ryan Davis pointed out that you can do something similar with flog and autotest by hard-coding this into your ~/.autotest file:

Autotest.add_hook :green do |at|
  system "flog app/controllers/users_controller.rb | grep \\#update" 
end

Incomprehensible Statistics

For completeness:

rstakeout  = 73.7304101610032
autotest   = 909.440236256987
ratio = autotest / rstakeout
      = 12.3346694297654   # <-- zomg! look here!!!

# I have no idea what these numbers are here for,
# or what they mean.
ratio - Math::PI
= 9.19307677617561

target = autotest / Math::PI
= 289.483818093921

target - rstakeout
= 215.753407932918

A Year of PeepCode!

Somehow, it’s been a year of PeepCode!

Yes, I’ll stop these self-congratulatory posts soon. In the meantime, buy a 10-pack and get 2 free screencasts, or a 5-pack and get one free. Offer good through Friday, September 7.

And the first PeepCode Press PDF is now available for purchase in draft form. Rails Code Review is seventeen chapters of common mistakes in Rails apps, and examples of how to write better code instead.

Finally, I have about 15 PeepCode t-shirts that were printed with an experimental process. Early users have reported that the printing washes off after the first laundering. But hey, at least you’ll have a nice black t-shirt! I’ll send you one at my expense, anywhere in the world.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Logo Redux

I received a lot of feedback, humor, and creativity in response to my article about an alternate community logo for Rails.

I received an official reply but don’t want to distort the ideas that were communicated, so I’ll let the people in question speak for themselves. However, the end result is that if you use Rails, you should be aware of the fact that the graphical logo representing Rails is trademarked. Developing an alternate logo isn’t going to be a worthwhile pursuit.

There are also some erroneous ideas that have been circulating. The good news is that you won’t be forced to pay any royalty to use the words “Ruby on Rails.”

Philosophical Reactions

As someone who appreciates graphic design, I think this is an interesting commentary on the power of visuals. People rally behind country flags, sports team mascots, and even company logos.

Even in the unemotional field of computer science, we want to be emotionally attached to a concept and a community. A visual logo is often the focus and expression of our enthusiasm for a technology. We want to wear it like a shield on our t-shirts and build our own company logos, blogs, and domain names around it (possibly in denial of how fast technologies change, or possibly in admission of how fast companies go out of business).

Maybe it was the more emotional among us who were disappointed to hear about restrictions on the use of a visual we had invested our hopes, dreams, and aspirations into. We think of open source software as a guerilla, anti-corporate endeavor and trademarks as a protective, corporate measure, so it’s hard to understand the two coming together.

In the end, we still value the seal of approval just as people have for thousands of years (both the owners and the recipients of the seal).

The Ruby Logo

So if you need a visual to rally around or tattoo on your ankle1, try the beautiful Creative Commons-licensed Ruby logo designed by the talented John Long.

David Black pointed me at the site for the Ruby Visual Identity Team which even includes a downloadable kit with copies of the logo in many known bitmap and vector formats.

There’s even a mailing list where you can ask Matz personally for permission to use the logo, which is often granted.


1 The Ruby logo is liberally licensed under the Creative Commons Attribution Share-Alike license. In my understanding of the license, this only applies to modifications on the logo itself and would not extend to your body after being tattooed with it.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Quick Sketches for an Alternate Logo That Can Be Used by All Developers Without Any Restrictions

...you’re always free to fork and call it Pete’s Swanky Framework, design a logo for PSF, and invite everyone to use that for whatever they like. – DHH

Just to get the conversation started…

Ring theme

Nuclear superhero theme

Pirate theme

Pete’s Swanky Framework

Resources


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

(Real) Social Networking with Ruby and Hardware

Scottie Project by Agile Dovadi and the Waag Society

At the Ruby en Rails conference in June, I spoke with Frank Oxener of Agile Dovadi who is working on some interesting hardware projects with Ruby.

They are using the small, inexpensive Arduino microcontroller boards together with some high-tech fabrication to build a non-verbal interface for children hospitalized with long-term illnesses to communicate with their parents.

The handheld unit communicates with a Mac mini via Bluetooth and notifies the parent over the internet.

I did a bit of circuit board fabrication in college and have been fascinated with projects like this. It’s great to see people taking innovative approaches and using technology to provide a meaningful benefit to people who need it.

Resources


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

On Microcelebrity

Most people are curious / and want to get dirt on / the Centaur, I’m famous / I walk around with no shirt on. – Buck 65

Somehow, I’ve managed to make a name for myself over the past few years. It’s a little freaky to casually mention on Twitter that I bought a new office chair, then to see people on an IRC channel on the other side of the world debating the positive and negative aspects of my chair.

I love meeting people at conferences and collaborating on interesting projects. But I get a lot of email and I’m not always able to respond to all of it.

If you’re hoping to write to me or any other microcelebrity, here are some suggestions that improve your chances of getting a response.

Email

General props, compliments, and thumbs up are always appreciated. Every other day I get an email with a thumbs up, which makes my job awesome. It’s one thing to have a boss pat you on the back, and another to get an email from an actual customer or fan who appreciates you. So thank you to all the people who have taken the time to pat me on the back!

For all other email, keep it short and include a specific action item. I received a wonderful email from someone about their history of learning Rails, their plans for the future, and about 6 other long paragraphs. I appreciate that someone took the time to write to me, but a long letter like that takes a while to read and it’s likely that I’ll put it aside and never come back to it.

Social Networks

When friending someone, include a short note about who you are. LinkedIn, Facebook, and other apps give you a spot to add a personal note when you add someone to your network. This puts things in context and helps me figure out if you’re an old college roommate or a friend of my mechanic. For readers of this blog, it could be as simple as the one word “Rubyist.”

This is even more important if your screen name doesn’t match your email address and your real name is even different from the other nickname you go by in the real world. I try to keep these things straight, but sometimes it’s like tracking down a con artist with 17 aliases. (If Jason Crane is reading this, I didn’t mean to call you a con artist!)

And if you are writing a social networking application, give your users a place to do that when they invite friends.

Consulting

I’m currently putting my full effort into PeepCode. If you’re trying to hire me for a long-term project, you’ll get a stock rejection letter, unfortunately.

However, I love to travel and am interested in the occasional on-site training session. I also love to speak at conferences and love it when a conference is organized well enough to pay for my plane ticket to the event.

Books

If you’ve recently published a book and want me to review it here or interview you on the Rails Podcast, I’d love to receive a copy of your book. My mailing address is in the footer of my blog.

Again, I’m putting my effort into my own publishing company right now, but I sometimes take the time to review other books in process. However, I’d much rather be part of the initial process before you even start the book. It’s awkward to send a critical letter of condemnation after reading a book that was poorly researched and badly implemented. I would much rather talk to you for an hour or two before you write your book to get you going on the right track. I’m saying this mostly for authors of anthologies who are going to cover Rails in a single chapter and want to cover only the basics.

Props to O’Reilly for Supporting Developers of All Genders

On a completely unrelated note, I want to give a thumbs up to O’Reilly for listening to the community. On the Rails Podcast, several women decried the lack of gender-specific t-shirts being printed and given out at conferences.

Thanks to unflagging internal advocacy by Rob Orsini, O’Reilly have tentatively announced that they will be printing women’s t-shirts for RailsConf in Berlin. I think this will be the first O’Reilly conference to do this.

Also, it pains me every time I go to the excellent DevChix blog and see that there are only a few hundred subscribers. Carmelyne Thompson, Ana Nelson, Desi McAdam, and others are writing some great articles there and you need to subscribe to their RSS feed if you haven’t already.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

TypeCon 2007 Seattle

At the table, left to right: John Downer, Spyros Zevelakis, Matthew Carter, Akira Kobayashi

I’ve been at TypeCon for the past three days (photos). I appreciate great type design, it was located here in Seattle, and I wanted to see how a non-tech conference was run.

It was satisfying on all accounts. Here are a few reactions of technical and non-technical interest.

Re-introducing unpredictability

One of the most provocative and mind-blowing lectures was by Robert Bringhurst, author of the classic Elements of Typographic Style (also being interpreted for the web).

His lecture on Typography as Quantum Mechanics explored the contrast of the predictability we get from mechanized systems with the unpredictability of reality. If you look at a handwritten document, you’ll see that not every instance of the letter ‘a’ is written in exactly the same way. This difference isn’t random but is part of the human element that distinguishes calligraphy from the output of a typewriter.

We’ve gotten into the habit of programming computers to reproduce the same result time after time, and in 99% of cases this is a good idea. But reality is not always predictable. The beauty of the situation is that current technologies such as OpenType make it possible to embed multiple variations of a letter into a font, and software can take advantage of this when rendering a document. For example, he showed an Arabic-language plugin for the InDesign page layout program that allows a designer to specify the probability with which different variations of a letter will be used.

How does this apply to website development? I’m not quite sure. We wouldn’t want to show random search results or pull a random article from a database. And, the point of the lecture was to achieve better aesthetic representation, not to change content.

Right now the concept that I’m chewing on is how to get the human element back into programmatically-generated content.

DRM deemed too costly by Adobe

In an afternoon panel, directors from Microsoft and Adobe answered a question about DRM. Apparently Adobe has tried three times to develop a copy protection system for fonts, but they have never completed it. The reason? They weighed the financial benefits against the user experience and determined that it was better to keep selling fonts without DRM.

A type designer who asked not to be named said that he knew his fonts were being pirated, but they also served as a sort of free advertising. People who did the pirating were probably not likely purchasers of his fonts anyway, and a person who discovered him via file-sharing networks might end up becoming a large-scale corporate licensee of his typefaces.

I believe in paying for quality software that I use. I paid US$1,600 for the Adobe suite that I use daily. The last font family I purchased cost about $400 and I would have gladly paid more.

I know that some episodes of PeepCode are being pirated, but I’ve chosen to sell screencasts without any DRM. Legitimate purchasers have converted the videos for their own use on other devices such as the Sony PSP, and Linux users who have subscribed have converted them to Flash video or other formats so they can view them more easily. I don’t want to punish legitimate users by restricting their ability to use content that they have paid for. It’s affirming to hear that the second largest software company in the world has also made the same decision.

Speaking of which, I’m now offering Team Licenses of PeepCode. Several companies have bought licenses for their development team or even their entire company. Each developer will receive a license code and can maintain an account at PeepCode, or you can choose specific screencasts and distribute them to your employees on your local network. Email peepcode@topfunky.com with the number of developers you would like to buy for, and how many screencast credits you would like to purchase.

Presentations, with audio!

As I hoped, most of the presentations communicated clearly and were delivered with style. Technically, the most amazing thing was the fact that every speaker had access to both video and audio amplification. Even more amazing was the fact that they actually used it!

The founder of P22 talked about the hand-printed covers for their companion record label, and he was able to play clips of the music he was talking about. John Downer impersonated one of his fonts for 20 minutes and used music to accompany the dramatization.

I’m taking bets on how long it will be until I attend a tech conference that provides every lecturer with audio amplification in addition to a video connector. In the meantime, people will continue to detach their lapel mic and press it against their laptop’s speaker anytime they want to show a video clip or play any audio. Or if you’re Adam Keys, you bring a live musician with you.

I’m putting together a separate article on how to create a top-notch presentation and will post it before RailsConf in Berlin.

Mikifiki

The F-bomb was surprisingly popular. It was dropped twice before lunch on the first day of lectures, and was presented to the audience 5 times by a single speaker on Saturday.

I’m not sure if David Heinemeier Hansson is into typography, but I can only guess that his single slide would have been a non-event at this conference.

Conclusion

I haven’t mentioned much about the rest of the artistic inspiration or personal conversations I had at the conference. Overall, it was a great experience. Next year’s will be in Buffalo, NY. There is also a related conference coming up this fall in Brighton.

I spoke with the conference organizers and I may be able to donate bandwidth to serve the audio recordings of the lectures. I’ll post here if that happens.


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.

Seattle.RBBQ 2007

It’s time again for a Seattle.rb event at my house. Last year we proved the existence of why the lucky stiff when he showed up for the last 30 minutes just as it was getting dark.

Technically this won’t be a barbeque since I don’t own one UPDATE Ryan Davis will be bringing a BBQ machine, so bring meat with you. I will provide drinks and probably pizza in my backyard.

It will happen on this Tuesday, July 17. You can come as early as 6 pm, and the sun goes down at about 9 or 9:30 pm.

If you are in the Seattle area or can catch a flight from the land of Greenlid, please come!

? Directions


PeepCode Screencasts – Learn Ruby on Rails and Javascript! Hour-long screencasts for $9.
next page »