Posts for April, 2005

Note for Typo + MarsEdit people

If you're using Typo with MarsEdit, and have been bitten by the can't edit my post after it's been published bug, you need to apply this patch or upgrade your Typo installation.

Thanks everyone with Ranchero and Typo that figured it out! We all know that ./script/console is cool but using it to edit your posts gets old quick.

Update - Just to prove it works!

  • April 25, 2005

Sorry, there are no things

You know when there's something in the back of your mind, something you want to check out that you never get around to? Here's one from why that just made my day!

things = [1,2,3] 

if things.each do |thing|
  puts thing
end.empty? then
  puts "no things!"
end

It takes the classic case of if there's things, use the things, otherwise do something completely different and makes it beautiful. This is extra handy in ERB since there's only three lines of logic instead of five. (Note using the for..in alternative as well).

<% if for thing in things %>
  <%= thing %>
  <% end.empty? then %>
    no things
<% end %>

Bonus points for anyone that can write the following more simply...

<% unless things.empty? %>
  <ul>
    <% for thing in things %>
      <li><%= thing %></li>
    <% end %>
  </ul>
<% else %>
  no things
<% end %>

Use ./script/console. It's good.

One of the cooler things about Rails has got to be ./script/console. It uses irb (tips) to load up your entire application in an interactive shell. It's a great debugging tool, and it's fun to play with your objects in real time. But even better; you can use it to get work done.

This blog uses typo, which has no admin interface (yet). Therefore, it has no easy way to create categories. For the last post, I wanted to create a new category called "Web". It doesn't get much easier than this:

 # % ssh fivesevensix.com
 # % sites/fivesevensix.com/latest/script/console production
 # % irb> Category.new(:name=>"Web").save

Compare that to loading up mysql, phpmysql, or even an admin interface.

Of course I want to add that category to my article, so how about:


% irb> Article.find_by_title("Taking care of old links").categories << Category.find_by_name("Web")

(Using Rails' dynamic finders means you can easily look up the records by an arbitrary field's value. Nice.)

These are incredible tools. Anyone trying to compare the Rails environment to something in PHP, Java, etc. had better keep that in mind. For me at least, the power of it wasn't instantly apparent, but it's something I find more uses every day.

Check out this great debugging story by Tobias for more good ideas

Use FeedBurner. It's good.

Well, Stopdesign beat me to it, but I'll second the vote for using FeedBurner if you do any kind of syndication.

I absolutely love the stats it provides. I haven't enabled all the features but just knowing these things is amazing:

  • Number of people subscribed to your feed
  • Number of clicks from feed to site for each article
  • Number of clicks from feed to site per day

It's been fun to see my daily circulation increase every day since launch. Thanks everyone for subscribing!

Taking care of old links

Rearranging your site while still supporting those old links floating around the 'net can be a challenge. I tackled it over the weekend (in Rails) and here's what I found.

Sure, you can simply customize public/404.html but that isn't much fun. It won't make use of your layouts, so you will have duplication. And, you won't be able to do interesting things with those unfound url's.

There were two things I wanted to accomplish here:

  • If the url contained .php, redirect to the url without a the file name. Even though I went to a lot of trouble to have clean url's on my old site, somehow I ended up with referrers linking to /foo/index.php. In that case, I want to redirect to /foo.
  • Any other un-found url's get a pretty page in the standard layout.

Start by creating a catch-all route in config/routes.rb. The condition enables it in production mode only, so you still get the routes error page during development.

map.connect '*path', :controller => 'application', :action => 'rescue_404' unless ::ActionController::Base.consider_all_requests_local

Then, write some code in ApplicationController. Mine catches various error states in "public" (production mode) and handles them. Any unknown url's get sent through the handle_error_paths method, where I look for those ugly .php paths and redirect appropriately.

def rescue_404
  rescue_action_in_public CustomNotFoundError.new
end

def rescue_action_in_public(exception)   
  case exception
    when CustomNotFoundError, ::ActionController::UnknownAction then
      handle_error_paths(@request.request_uri)
      render_with_layout 'shared/error404', 'layouts/standard', '404'
    else
      @message = exception
      render_with_layout 'shared/error', 'layouts/standard', '500'
  end
end

def handle_error_paths(path)
  redirect_to_url path.gsub(/^(\/.*?)\/?\w+\.php/, ''), true if path.match /\.php/
end

Now, to test this thing you have two options. Switch to production mode, or mess with development mode. Switching to production mode is simple, but you can't change-and-reload, so making adjustments is annoying. Here's how I made development act like production for our purposes.

Modify config/environmenets/development.rb:

ActionController::Base.consider_all_requests_local = false

Then (re) define one more method in ApplicationController.

def local_request?
  false
end

Now, it won't see your 127.0.0.1 address and give you development error messages. You can probably leave that method, but be sure to change consider_all_requests_local to true when you get back to regular work.

That should do it. This wasn't nearly as easy as I'd have liked it to be but in the end, not too bad. A little bit of patching to the Rails source could make this much better.

If there's an easier way, please share.

Staying Extra DRY

Sometimes you need a little tiny function to avoid repetition. Here's a partial called packet I made.

I needed the same id for the element and the Javascript call so I pulled the id-building logic into a lambda. Now they'll never be mismatched.

<%
  pid = lambda do
    "packet-" + packet.code.downcase.gsub(/[^a-z]/, '-')
  end
%>
<dt><%= link_to_function packet.name, "Toggle.display('#{pid.call}')" %></dt>

<dd id="<%= pid.call %>" style="display: none;">
    Things about the packet.
</dd>

Yes, the id-building logic here is a bit contrived but you get the idea. For more widespread things like this I'd pull it out into a helper, but this one just didn't need it.

Automatic body tag id with Rails

Sometimes you want to style a certain page (or a certain element of a certain page) differently than others. The easiest way to do that is to give a unique id to the body tag.

In your stylesheet you say something like:

body#my-unique-id a.rule {
  background-color: #f00;
}

Which, of course, makes that particular selector only apply to one page. As with everything, this is really easy to do in Rails. You can put something like this in application_helper.rb:

def bodytag_id
  a = controller.class.to_s.underscore.gsub(/_controller$/, '')
  b = controller.action_name.underscore
  "#{a}-#{b}".gsub(/_/, '-')
end

It simply takes the current controller and action, say MyController#the_action and converts id to my-controller-the-action. I prefer dashes in class names and id's. Personal preference.

Call it in your layout:

<body id="<%= bodytag_id %>" class="standard">

I like to give each layout a unique class name as well, to differentiate them in the same kind of way. Now every page on your site has the hooks necessary to customize its style.

Hello world and something clever

This is the first post to the first blog I ever put online.

That's not to say I've never designed a blog, coded a blog, or even written blog entries. I've done all that. No, this is just the first one I ever finished well enough to share with you. So what was different this time?

It's going to sound cliché, but, honestly, it was Ruby on Rails. Up until two months ago I had been working in Java with Spring and Hibernate. Programming was becoming a chore. It wasn't something I stayed up all night to do because I loved it; I was staying up all night wrestling with Tomcat/Eclipse/JSTL/Spring/Hibernate/Acegi/etc.

Before those dark days of Java, I worked in PHP. I wrote countless web platforms in PHP for fun, a couple of those even became real sites. They had nice features, were pretty flexible and extensible. They were based on many of the same ideas as Rails, but were never something I would call elegant. PHP just lacks that certain something.

So about two months ago, shortly after attending the Building of Basecamp workshop in Seattle, I gave in and decided to see what this Ruby hype was all about. Long story short, about three days later I decided to stop all Java development and convert existing projects to a language I'd only heard about days before.

This site is here because programming is fun again. Thanks Matz and David.