Posts dealing with rails

This isn’t Typo

Thought I should mention that this site isn't using Typo anymore. It had been running on a very old, and heavily customized version which made it extremely hard to upgrade. I started looking at converting to new version with themes and felt like it was overkill. What was once little Typo has really grown into a non-trivial app.

Instead, I whipped up something really simple called Post. A short list of features..

All in 431 lines of code and 423 lines of test. Remember when this stuff was hard?

Careful what you name things

On Friday I decided to create a new class called Failure. A Failure is stored anytime an unexpected exception is raised in our application. There are various subclasses to indicate many specific types of failures such as FrontendFailure and BackendFailure, each of which has different behavior. For example, FrontendFailure might send e-mail after_save. Other failure classes represent expected but unhandlable errors like "your template code is wrong". In those cases we can e-mail the user. We could even look through the failures to see if the user's problem has been fixed yet.

The failures table. (data is a serialized OpenStruct so subclasses can store anything they like)

create_table :failures do |t|
  t.column :type, :string
  t.column :exception_class, :string
  t.column :exception_message, :string
  t.column :backtrace, :text
  t.column :message, :string
  t.column :data, :text
  t.column :status, :integer
  t.column :created_at, :datetime
  t.column :updated_at, :datetime
end

Sample usage.

begin
  do_something_big_and_complicated
rescue ComplicatedError => e
  ComplicatedFailure.occurred e, "it happened again"
end

Ok, so this works great. No problems. The problem was more subtle. Really subtle.

As I worked on this bit of code and started using it to debug various features, I started getting depressed. Not slit-your-wrists depressed but definitely bummed. Having just read Malcolm Gladwell's excellent Blink I can only say it was from constantly reading, typing, and thinking about "failure" over the course of a few hours.

Hacking Dispatcher without DI

For reasons I won't get into, it became necessary to make Rails go faster. But only for a couple url's, and without need for the majority of the framework. For a while, we ran these scripts with raw FCGI and a simplified Dispatcher that let you work with the request and response directly, bypassing the main Rails workflow.

But now we have the wonderful RailsFCGIHandler, with graceful signal handling, app reloading and more. I wanted our custom dispatcher to benefit from that too.

So, we want to use the RailsFCGIHandler but handle requests with our stripped down Dispatcher before Rails gets to it. My first thought was to override FCGIHandler#process_request

class CustomRailsFCGIHandler
  def process_request(cgi)
    MyDispatcher.dispatch(cgi)
    # Dispatcher.dispatch(cgi)
  rescue Object => e
    raise if SignalException === e
    dispatcher_error(e)
  end
end

CustomRailsFCGIHandler.process!

That's ok, but we've duplicated some tricky exception handling logic. Even worse, it's treating Ruby like a static language. We can do much better. First, there's no need to subclass RailsFCGIHandler. Simply opening the class and redefining process_request would do the same thing.

But, here's the cool part. We don't have to modify RailsFCGIHandler at all! The only functionality we need to change is in Dispatcher, so let's just modify it.

class Dispatcher
  class <<self
    alias :old_dispatch :dispatch
  end
  def self.dispatch(cgi)
    SimpleDispatcher.dispatch(cgi,false) do |request, response|
      case request.path
        when "/one" then Tracker::Controller.process(request, response, :one)
        when "/two" then Tracker::Controller.process(request, response, :two)
        else old_dispatch(cgi)
      end
    end
  end
end

RailsFCGIHandler.process!

That's it. Now our two high-availability url's are handled while still supporting Rails' normal workflow.

Here's SimpleDispatcher for reference. All it does is instantiate Rails' request and response objects, yield them, then take care of session propagation and write a response.

class SimpleDispatcher
  def self.dispatch(cgi = CGI.new, session_options = ActionController::CgiRequest::DEFAULT_SESSION_OPTIONS)
    request, response = ActionController::CgiRequest.new(cgi, session_options), ActionController::CgiResponse.new(cgi)
    begin
      yield request, response
    rescue
      response.body << $!.to_s
    ensure
      request.session.update if request.session && !request.session.kind_of?(Hash)
      response.out unless response.body.empty?
    end
  end
end

Back to Dependency Injection. In a static language, hardcoding Dispatcher.dispatch(cgi) would have been a sin. It forever ties us to a specific implementation. Design patterns help - template method or factory method come to mind. Or using a DI container with setter injection. But each of these techniques causes excess overhead in both usage and design.

The Ruby way gives us a simple (almost naïve) implementation that's as flexible as the most complicated architectural patterns.

This point is worth repeating. Without any coding or design overhead, the result is highly flexible. Sure you can accomplish the same result in Java, et al but how many more lines of code+config+tests did it take?

FOSCON

FOSCON was great. Thank you pdx.rb for putting on the event!

Keep an eye out for Rails/Flash integration using a Cocoa-like windowing system. Amazing, made-me-drool stuff. And all he showed was sample code.

Glenn Vanderburg's talk on domain specific languages for programmers was enough to make me rewrite a large chunk of code as soon as I got home. Update slides here

_why's performance was something to be seen. Truly.

CalendarGrid 1.0.1

CalendarGrid 1.0.1 is a major bugfix to 1.0. Please upgrade now. If you tried 1.0 and were utterly disappointed, I apologize.

Note to Rails users. Never ever rely on the nifty date math methods for real date calculation. Try this:

Time.local(2005,10,30) + 1.day
=> Sun Oct 30 23:00:00 PST 2005

Um, what?

1.day
=> 86400
Time.local(2005,10,30) - Time.local(2005,10,29)
=> 86400.0
Time.local(2005,10,31) - Time.local(2005,10,30)
=> 90000.0

Lesson learned. Be careful with dates. This all came about because I switched from using Date to Time for everything internal.

Just in case anyone doesn't know how slow (but accurate!) Date is...

bm do |x|
  x.report("Date.today") do 
    1000.times { Date.today }
  end
  x.report("Time.now") do 
    1000.times { Time.now }
  end
end
            user       system     total       real
Date.today  0.420000   0.010000   0.430000 (  0.452072)
Time.now    0.000000   0.000000   0.000000 (  0.003978)

Thanks to Ben Bleything for the heads up!

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

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.