The 7 main actions we took to improve the Rails stack performance at Justin.tv

Here are the slides of the talk I gave at the San Francisco Rails meetup group yesterday about the work we have done on improving Rails performance at Justin.tv

Enjoy!

  • Share/Bookmark

Rails3 ActiveSupport Notification subscription – Rails3 Tricks #03

Hello there! Almost 10 months without any post due to a very busy period: I moved from Paris to San Francisco.
Ok, so now facts has been said, this will hopefully change! I plan to write a new series of Rails3 posts, starting with a quick one on the new way Rails handles notifications.

The new version of ActiveSupport shipped with Rails brings along a new notification system which is heavily used by Rails3 internarlly. Rails doesn’t write directly to logs anymore, instead of that, it publishes a notification which can be caught by any observers.

In production, Rails will by default publish deprecation warnings through this notification system. Last week I was looking for a way to play with that and didn’t find a clear example on the web, so here is a small snippet of code if you are also looking for a nice way to log your deprecation warnings:


# In config/initializers/deprecations_logger.rb
DeprecationLogger = Logger.new(Rails.root.join('log/deprecations.log'))

ActiveSupport::Notifications.subscribe(/deprecation/) do |type, date,b,c, event|
  DeprecationLogger.info("#{date} - #{event[:message]}")
end
  • Share/Bookmark

Rails3 and will_paginate, Doing easy remote links – Rails3 Tricks #02

As you know, Rails3 use only UJS (unobtrusive javascript), so for every remote link, Rails3 just add the data-remote attribute to links :

<a href="ajax_page.html" data-remote="true">A remote link !</a>

If you want to do ajaxed pagination, there is no easy way with will_paginate to do remote link (or I didn’t find any one), but with Rails3 UJS, there is a little tricks do to this easily !

Here is the haml and jquery code :

= will_paginate(@users)
:javascript
  $('.pagination a').attr('data-remote', 'true');

This snippet of code just add the attribute data-remote to pagination links. And that’s it ! Our pagination will now be ajaxed :)

  • Share/Bookmark

Using Rspec with multiple version of Rails – Rspec Tricks #01

With the upcoming release of Rails3, it’s important to maintain gem/plugins compatibility with both Rails 2.x series and the new Rails 3.x series.

That’s why I wanted to implement specs supporting both versions for one of my plugin.

With a simple rake task, I wanted to run spec for a specific Rails version.

By default, Rspec create this kind of Rakefile :

require 'rubygems'
require 'rake'
require 'spec/rake/spectask'
 
spec_files = Rake::FileList["spec/**/*_spec.rb"]
 
desc "Run specs"
Spec::Rake::SpecTask.new do |t|
  t.spec_files = spec_files
  t.spec_opts = ["-c"]
end
 
task :default => :spec

Here we have the default Rake task : “spec” wich will run specs for our code.

Custom our Rakefile to specify the Rails version

At this point, we need to pass an extra option to spec script in order to specify wich rails version we want to use in our tests.

The way I found to do this is to tricks spec_opts (which is command line options for spec) by assigning to it, a Proc, like this :

t.spec_opts = lambda do
  @rails_version ? ["-c -- rails_version=#{@rails_version}"] : ["-c"]
end

Then add two tasks to your Rakefile :

desc "Run Rails 2.x specs"
task :rails2_spec do
  @rails_version = 2
  Rake::Task['spec'].invoke
end

desc "Run Rails 3.x specs"
task :rails3_spec do
  @rails_version = 3
  Rake::Task['spec'].invoke
end

Ok, now we have our three tasks passing Rails version to our spec tests !

kwi@ ~/Projects/i18n_routing$ rake -T
(in /Users/kwi/Projects/i18n_routing)
rake rails2_spec  # Run Rails 2.x specs
rake rails3_spec  # Run Rails 3.x specs
rake spec         # Run specs for current Rails version

Retrieve the Rails version parameter

Then in your spec_helper.rb file, where you include your dependencies, you just need to retrieve the rails version with this (dirty) piece of code :

rails_version = ARGV.find { |e| e =~ /rails_version=.*/ }
rails_version = rails_version.split('=').last.to_i rescue 2

Now we have the correct rails version we want for running our tests, so we need to include our dependencies depending on the Rails’ version we want to load.

For this, there is a tricky things with gem method for specify wich version of gem you want to use :

gem 'actionpack', (rails_version < 3 ? '< 2.9' : '> 2.9')
require 'action_controller'

(Example for loading action_controller only, here I use 2.9 version number in order to support Rails3beta)

Here we are, now we can run our tests on both Rails version just with a simple rake task :

rake rails2_spec
# Or
rake rails3_spec
  • Share/Bookmark

Rails 3 edge routing – Rails3 Tricks #01

Here are just two little issues I encoutered today when I worked on Rails 3 edge routes. I think it can be useful to share them.

I assume you already know changes in routes for Rails3.
(if not, watch: Ryan Bates Screencast about routing in Rails3)

Declare your root path

Matching empty route string are now impossible in Rails 3 edge (not in beta yet), so you can not do anymore :

MkdBaseApp::Application.routes.draw do
  match '' => "home#show", :as => :home
end

Instead, you need to use root :

MkdBaseApp::Application.routes.draw do
  root :to => 'home#show', :as  => :home
end

Route Globbing

Route globbing is a way to catch any action matching a part of an url. It’s useful for catching errors for example.

In Rails 2, it was with connect

ActionController::Routing::Routes.draw do |map|
  map.connect "*path", :controller => 'error', :action => 'handle404'
end

In Rails 3, it’s pretty the same, but with match :

MkdBaseApp::Application.routes.draw do
  match "*path" => 'error#handle404'
end

Put this snippet at the end of your routes declaration and the ErrorController will be called if not routes match the requested uri.

Remove the map variable

Remember that you do not need anymore to get the map variable in your route block :

Rails 2:

ActionController::Routing::Routes.draw do |map|
  map.resources :users
end

Rails3, remove the |map| :

MkdBaseApp::Application.routes.draw do
  resources :users
end
  • Share/Bookmark

jQuery 1.4.2 is Out, it’s again blazing fast !

Yesterday, the jQuery team has released a new version of its famous javascript library, and again, it’s rock competitors :)

jQuery benchmarks vs competitors

A good start for succeed your projects, it’s using good tools. And jQuery is one of them.
So, do not wait, and start using the today best javascript library !

For Rails 3, use jQuery UJS :

Use the jQuery official UJS plugin : http://github.com/rails/jquery-ujs, explanations for usage on another blog : http://blog.datagraph.org/2010/02/jquery-with-rails-3

And do not forget to use the helper csrf_meta_tag in your header in order to output metas for the authenticity token.

For Rails 2.x, use Jrails :

Install the drop-in remplacement jrails plugin: http://github.com/aaronchi/jrails

  • Share/Bookmark