Breaking the Rails static asset timestamp cache in development mode

Rails automatically adds the File.mtime to static assets when using stylesheet_link_tag and javascript_include_tag. The file’s mtime is cached to prevent excessive file system access… even in development mode. This is problematic in a Facebook canvas during development mode because often you won’t immediately see the changes you make to your stylesheets and javascripts.

Here is a monkey patch you can throw into a config/initializers/break_asset_cache_in_dev_mode.rb to fix this:

if RAILS_ENV == 'development'
  require 'action_controller/dispatcher'
  ActionController::Dispatcher.before_dispatch do
    ActionView::Base.computed_public_paths.clear
  end
end

Cleaning up old releases

Instead of relaying on running cleanup of old releases via capistrano, we have a cron job to only keep releases for last two days (but at least three latest).

#!/usr/bin/env ruby

require 'fileutils'

KEEP_RELEASES = 3
KEEP_DAYS = 2
EXCLUDE_APPS = %W(uploadr)

cut_time = (Time.now.utc - KEEP_DAYS*24*60*60).strftime("%Y%m%d%H%M%S").to_i

Dir['/u/apps/*'].each do |app|
  next if EXCLUDE_APPS.include?(File.basename(app))
  dirs = Dir["#{ app }/releases/*"]
  fresh = dirs.select { |dir| (dir.split('/').last).to_i > cut_time }
  latest = dirs.sort.last(KEEP_RELEASES )

  (dirs - fresh - latest).each do |dir|
    FileUtils.rm_rf dir
  end
end

Rake task for syntax checking a Ruby on Rails project

Here’s a quick rake file that will crawl through your Rails project and syntax check ruby, erb, and yml files. You should always run this before doing a “cap deploy” and it even doesn’t hurt to run it before a “svn commit”.

require 'erb'
require 'open3'
require 'yaml'

task :check_syntax => [:check_ruby, :check_erb, :check_yaml]

task :check_erb do
  (Dir["**/*.erb"] + Dir["**/*.rhtml"]).each do |file|
    next if file.match("vendor/rails")
    Open3.popen3('ruby -c') do |stdin, stdout, stderr|
      stdin.puts(ERB.new(File.read(file), nil, '-').src)
      stdin.close
      if error = ((stderr.readline rescue false))
        puts file + error[1..-1]
      end
      stdout.close rescue false
      stderr.close rescue false
    end
  end
end

task :check_ruby do
  Dir['**/*.rb'].each do |file|
    next if file.match("vendor/rails")
    next if file.match("vendor/plugins/.*/generators/.*/templates")
    Open3.popen3("ruby -c #{file}") do |stdin, stdout, stderr|
      if error = ((stderr.readline rescue false))
        puts error
      end
      stdin.close rescue false
      stdout.close rescue false
      stderr.close rescue false
    end
  end
end

task :check_yaml do
  Dir['**/*.yml'].each do |file|
    next if file.match("vendor/rails")
    begin
      YAML.load_file(file)
    rescue => e
      puts "#{file}:#{(e.message.match(/on line (\d+)/)[1] + ':') rescue nil} #{e.message}"
    end
  end
end

And here’s what the output looks like:

warren:tmp_project$ rake check_syntax
(in /Users/warren/tmp_project)
app/controllers/application.rb:37: syntax error, unexpected '='
app/views/people/home.html.erb:60: syntax error, unexpected '<', expecting $end
vendor/plugins/will_paginate/test/fixtures/users.yml:13: syntax error on line 13, col 0: `dev_<%= digit %>:'

This could probably be expanded to support lots of other types of files as well (css, javascripts, etc).

Updates:

  • Exclude all files in vendor/rails (thanks szeryf)

ESI & Mongrel-ESI.. Request for Feedback



The Railsconf08 talk on ESI & Rails has sparked some interest in the community, and Todd, the core mongrel-esi maintainer, is asking for feedback on the mongrel-esi mailing list.

The latest rumor is he is working on a nginx port of mongrel-esi, which I have to admit sounds very interesting…

How are people planning to use ESI? Can anyone provide Todd with some feedback?

  I'm wondering what is the main set of features preventing folks
today from using mongrel-esi in production?  Is it :

* performance
* documentation
* stability

If it's performance, can someone do some load testing maybe provide
some numbers and even some target numbers?  I am working on an
improved concurrency model, that should help improve page performance
for pages with lots of esi:include tags

if it's documentation, what's the missing bits, and can any of you
help out by filling in the gaps?

if it's stability, can you provide some samples that fail?

-Todd

RailsConf 2008 Presentation – Assembling Pages Last



I presented this morning at RailsConf about Edge Caching and ESI. You can download my presentation below.


Assembling Pages Last: Edge Caching, ESI, and Rails

People asked some awesome questions, caught the edge cases I didnt want to cover which were complicated, like authorization/security, multi-level ESI includes, per page include limits, etc. The people at RailsConf are awesome. Thats totally why I enjoy these events.

The End of Slideshows: Animoto

UPDATE: Animoto just raised a round of investment from Amazon! Congrats Guys!

Animoto is a great idea. They take your photos and create a production quality video to the music of your choice. Its the end of those boring slide shows, for good.



(From a recent Techcrunch article here)

We had the pleasure to work with the Animoto guys to launch their Facebook application, “Animoto Videos”, which leveraged all of the existing photos on Facebook. The growth was amazing.



(From a recent AllFacebook article here)

Scaling an application from a few hundred users to over a million in just a few days isnt easy, but we had a great team. Their backend rendering farm lived in Amazon’s Cloud, and the growth was so impressive, Jeff Bezos even spoke about them at Y Combinator’s Startup School just a few weeks ago. From 50 EC2 instances to over 4k in only a few days. See the video below.

<div><a href='http://www.omnisio.com'>Share and annotate your videos</a> with Omnisio!</div> <p>

It was a pleasure working with the entire team from Animoto, RightScale, and Amazon. See their blog posts about the application here, here, and here.

I’m sure I’ll cross paths with many of you at RailsConf. First round of beers is on me.