Bhushan

Just another weblog from Bhushan Ahire

Ruby on Rails Advanced Page Caching

Posted by Bhushan G Ahire on August 24, 2007

Ruby on Rails (RoR or Rails) has some cool caching mechanisms already built in. You can cache parts of pages (fragment caching) or whole pages (action caching) while still going into your Rails code to check for permissions or do other things. However, for the highest performance, you can use page caching which serves the web page without even starting Rails, making it incredibly fast. For instance, on my slow computer, doing action caching was 2 times faster than normal, but doing page caching was 30 times faster! (See Ruby on Rails Caching Benchmarks).

However, the problem I ran into was that when you are logged into my wiki as an editor, you see an “Edit” link on each section of the page, and if you are logged in as an admin, you see an “Admin” choice on the menu. So while the Rails action caching would work fine for this, I couldn’t use the Rails out-of-the-box page caching since if I was logged in as an Editor and browsed through the pages, the next person that looked at the pages would still see all the “Edit” links, even if they were not logged in!

After some thought, I came up with two solutions for solving this problem. The first was based on rewriting the URL depending on what role the user is logged in as. I then came up with a better method that relies on setting a cookie with the current role and then using Javascript to modify the page appropriately. Here are the details on both methods.

URL Rewriting

The first solution for Rails advanced page caching is based on rewriting the URL depending on what role the user was logged in with.

The basic steps in this method are:

  1. Add a route in routes.rb to include the role in the URL
  2. Pass the role to all url_for calls
  3. In a before_filter in application.rb, redirect to the correct page based on the current role
  4. When expiring a page, expire all the roles for that page
  5. Turn on page caching and sweeping

To be able to cache pages that are different based on what role the use is logged in as, the routing rules are rewritten so that the role is included in the URL. For instance, here is how the URLs will look:

First, you need to add a “_role” route to routes.rb, something like this:


DEFAULT_WEB = 'wiki' unless defined?(DEFAULT_WEB)
ActionController::Routing::Routes.draw do |map|
  map.connect 'rss_with_headlines', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'rss_with_headlines'
  map.connect 'rss_with_content', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'rss_with_content'

  map.connect '_role/:role/:id', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'show'
  map.connect '', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'show', :id => 'HomePage'
  map.connect 'index.htm', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'show', :id => 'HomePage'
  map.connect ':id', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'show'
  map.connect '_edit/:id', :controller => 'wiki', 
    :web => DEFAULT_WEB, :action => 'edit'
 map.connect '_action/:controller/:action/:id', 
    :web => DEFAULT_WEB
end


(For more information about this routing table, see Ruby on Rails Better Wiki URLs

Simple enough? Now the trick is that we want this route to be used if there is a role set, but otherwise use the other routes. So we need to pass in a role name to all procedures that create URLs, something like this:


href = @controller.url_for :controller => 'wiki', :web => web_address, 
:action => 'show', :id => name, :role => @controller.session_role
%{<a class="existingWikiWord" href="#{href}">#{text}</a>}

Next we need to make sure that the correct pages are appearing for the users current role. This is done in a before_filter in application.rb with code like this:

if (params[:action] == 'show') and (session_role != params[:role])
    redirect_to :role => session_role, :id => params[:id]
end

Then when a page changes, we need to expire that page in all roles:

def expire_page_in_all_roles(web, page_name)
  ([nil] + MY_CONFIG[:roles]).each do |role|
    expire_one_page(web, page_name, role)
  end
end

Finally, turn on page caching and sweeping in your wiki controller:


  caches_page :show, :published, :authors, :recently_revised, :list
  cache_sweeper :revision_sweeper

There are several limitations with this method:

  1. It is not secure. A user could change the URL to access a cached page under a different role. (For my application, this is not an issue since this would just show links and if they clicked on the link, they would still have to login.)
  2. If a user bookmarks a page when they are logged in, if they log out and then use the bookmark to go back to the site, the wrong page will be shown
  3. The URLS are longer than normal if you are logged in
  4. Caching is not as efficient since a new page needs to be generated for each role

Posted in Uncategorized | Leave a Comment »

Silverlight (and Ruby on the .NET CLR)

Posted by Bhushan G Ahire on August 23, 2007

Silverlight

At MIX07 a few days ago, Microsoft announced “Silverlight“, a new Flash-esque .NET-based platform for delivering “media experiences” and “rich interactive applications” on the Web. It’s interesting, and some people seem to think it’s going to revolutionize the Web, but that’s not why we’re interested in it at Ruby Inside.

The most interesting part of the Silverlight announcement is that it’s based on a subset of the CLR (Common Language Runtime) from Microsoft’s .NET platform. The .NET CLR has become a common target for programming language runtimes recently, but Microsoft has officially announced C#, Javascript, VB, Python and Ruby support for Silverlight’s CLR. Microsoft are also adding new features in a system called the DLR (Dynamic Language Runtime) to bring more dynamic features (as required by Python and Ruby) to the CLR. InfoQ has more information on this, in terms of Ruby.

What all of this means is that there’s baked-in support for Ruby in what could be one of the biggest runtime environments on the Web in the next few years, and this can only be a good thing for Ruby. Jon Udell sat down with John Lam (the creator of RubyCLR) and talked about the DLR, Ruby, and how the whole caboodle works / will work.

Let’s cross our fingers and hope this isn’t ActiveX all over again.

Posted in Uncategorized | Leave a Comment »

relative_time_helpers Plugin: time_ago_in_words on Steroids

Posted by Bhushan G Ahire on August 23, 2007

From Basecamp's screenshot

relative_time_helpers is a straightforward, but very useful Rails plugin by Rick Olson that formats timestamps to human-friendly relative dates. You’re probably already using Rails’ built-in time_ago_in_words helper in your applications, but Rick’s relative_time gives even better results:

<%= relative_time(Time.now) %>
# today
<%= relative_time(1.day.ago) %>
# yesterday
<%= relative_time(1.day.from_now) %>
# tomorrow
<%= relative_time_span([Time.now, 5.days.from_now]) %>
# May 17th - 22nd

To install it:

script/plugin install http://ar-code.svn.engineyard.com/plugins/relative_time_helpers

Posted in Uncategorized | Leave a Comment »

Rails performance tip – using YSlow

Posted by Bhushan G Ahire on August 23, 2007

YSlow from Yahoo! is a Firefox add-on to analyse web pages and tell you why they’re slow based on rules for high performance web sites. YSlow requires the indispensable Firebug extension.

The 13 rules YSlow checks your site against are as follows:

1. Make Fewer HTTP Requests
2. Use a Content Delivery Network
3. Add an Expires Header
4. Gzip Components
5. Put CSS at the Top
6. Move Scripts to the Bottom
7. Avoid CSS Expressions
8. Make JavaScript and CSS External
9. Reduce DNS Lookups
10. Minify JavaScript
11. Avoid Redirects
12. Remove Duplicate Scripts
13. Configure ETags

This post will demonstrate that most of these are easily achievable for a Rails website through a combination of plugins and with correct configuration of a proxy web server (in front of a mongrel cluster) – in this case Nginx. This guide follows experience with improving performance for trawlr.com (an online RSS reader).


Make Fewer HTTP Requests, Minify JavaScript, Put CSS at the Top, Move Scripts to the Bottom, Remove Duplicate Scripts

The easiest way to make fewer HTTP requests is to combine all JavaScript and CSS files into one. The asset packager plugin does exactly this, plus it will also compress the source files (in production mode) and correctly handles caching (without query string parameters).

Moving CSS to the top (within the head section) and moving JavaScript to the bottom of the page are both manual tasks that should be done in the layout templates (such as app/views/layouts/application.rhtml). Remember to use stylesheet_link_merged :base and javascript_include_merged :base rather than the default Rails helpers.

By using asset packager you can also verify that scripts are only included once – another performance hit otherwise!

Excluding the Google analytics JavaScript file, trawlr.com now uses a single css and js file (including the entire prototype library). Note: You may need to add a missing semi-colon as per this defect for prototype to work correctly.

Asset Packager can be included as part of a Capistrano deployment with the following recipe:

desc "Compress JavaScript and CSS files using asset_packager" 
task :after_update_code, :roles => [:web] do
run <<-EOF
cd #{release_path} &&
rake RAILS_ENV=production asset:packager:build_all
EOF
end

Use a Content Delivery Network

Ignoring this point for now; I’d suggest the use of Amazon S3 as a useful starting point for simple CDN.


Add an Expires Header


A first-time visitor to your page may have to make several HTTP requests, but by using the Expires header you make those components cacheable. This avoids unnecessary HTTP requests on subsequent page views. Expires headers are most often used with images, but they should be used on all components including scripts, stylesheets, and Flash components.

Nginx allows adding arbitrary HTTP headers via the expire and add_header directives. Adding the expires header to static content is done with a regular expression looking for relevant file extensions in the request URL. This example uses the maximum expiry date but could be set to more appropriate values as required (e.g. 24h, 7d, 1M)

# Add expires header for static content
location ~* \.(js|css|jpg|jpeg|gif|png)$ {
if (-f $request_filename) {
expires max;
break;
}
}

Gzip Components

Nginx can gzip any responses – including those proxied from a mongrel cluster.

gzip on;
gzip_min_length 1100;
gzip_buffers 4 8k;
gzip_proxied any;
gzip_types text/plain text/html text/css application/x-javascript text/xml application/xml application/xml+rss text/javascript;

Avoid CSS Expressions

Just don’t do it!


Make JavaScript and CSS External

Add you JavaScript and CSS styles in external files rather than inline. The added benefit here is that the content will be merged and compressed thanks to the work already done above.


Reduce DNS Lookups, Avoid Redirects, Configure ETags

These weren’t an issue for me so I suggest the Yahoo! guidance for further information

Reduce DNS Lookups

Avoid Redirects

Configure ETags

Posted in Uncategorized | Leave a Comment »

Calendar Date Select: A Lightweight, Prototype-based Date/Time Picker for Rails Developers

Posted by Bhushan G Ahire on August 23, 2007

Calendardateselect

Calendar Date Select is a new(ish) “date and time picker”, developed by Tim Harper, designed primarily for developers to use in Rails applications. It uses the standard Prototype JavaScript library, and is easily installed as a Rails plugin:

script/plugin install http://calendardateselect.googlecode.com/svn/tags/calendar_date_select

Take a look at the collection of demos of the picker to see its full range.

Posted in Uncategorized | Leave a Comment »

10 Great New Ruby / Rails Screencasts from July 2007

Posted by Bhushan G Ahire on August 23, 2007

Randscrcast-1

Railscasts, maintained by Ryan Bates, continues to release one great free screencast after another, with 9 so far this month, although we’re going to include one from June 29 for good measure. We first looked at Railscasts a few months ago, so if you haven’t visited again since, it’s worth it. Here are the latest screencasts:

  • Testing Without Fixtures – Fed up with using fixtures for your tests? Find a better way.
  • will_paginate – A look at the “new way” to do pagination in Rails using the will_paginate plugin.
  • Updating Through Checkboxes – How to perform actions on multiple items selected with checkboxes in a Rails view.
  • Handling Exceptions – Learn about exceptions and how to handle them in Rails apps.
  • The Logger – No, it’s not about felling trees. Learn how to send messages to the log and how to customize it.
  • How to Make a Generator – A look at building your own generator, much like the ones that come with Rails.
  • Optimistic Locking – How to resolve situations when two people want to update the same record at the same time.

At the same time, Geoffrey Grosenbach, curator of PeepCode (and a new sponsor of Ruby Inside), has been storming ahead with his own set of screencasts, a few of which will be of direct interest to Rubyists / Rails developers:

  • rSpec Basics – A look at Behavior Driven Development. An ideal starting point if you haven’t touched BDD yet but have been intrigued.
  • Rails From Scratch: Part I – A great up-to-date introductory “course” for getting into Rails. Even includes a free 20 page reference guide to Ruby and Rails, and an introduction to Ruby syntax. It’s everything a new Rails developer needs.
  • Rails From Scratch: Part II – Another 80 minutes of great introductory material for new Rails developers.

While Railscasts’ screencasts are totally free, Peepcode screencasts cost $9 each, but for the great packaging, length, and total depth of the material covered, they’re still bargains!

Posted in Uncategorized | Leave a Comment »

How to Profile Your Rails Application and Make Rails Go Vroom!

Posted by Bhushan G Ahire on August 23, 2007

Call Graph-1

Charlie Savage, author of ruby-prof, recently baked in support for Rails to ruby-prof, so now it’s possible to profile your Rails application, see where the delays are, and work on improving performance.

Hot on the heels of this development, Charlie wrote “How to Profile Your Application“, an article that does just what it says on the tin, and which demonstrates how to profile the CPU time used on a single Rails request, and visualize the call tree.

This was quickly followed up with “Making Rails Go Vroom“, another great article that looks at what parts of Rails significantly slow things down. Charlie comes up with six key suggestions:

  • Don’t use ActiveRecord#attributes or ActiveRecord#read_attribute
  • Get your :includes right
  • Don’t check template timestamps ( cache_template_loading = true)
  • Don’t use url_for
  • Don’t let Rails parse timestamps
  • Don’t symbolize keys (local_assigns_support_string_keys = false)

Learn more and see how Charlie came to his conclusions in the article.

Posted in Uncategorized | Leave a Comment »

How To Scrape Google With Ruby In 0 Seconds

Posted by Bhushan G Ahire on August 23, 2007

Scrubytgoogle

Okay, his title is a bit misleading, but Peter Szinek, developer of Ruby scraping toolkit scRUBYt!, has put together a great article showing the process, from start to finish, of scraping Google results using Ruby “in no seconds”. In reality, it’ll take you at least sixty to read the post.

Posted in Uncategorized | Leave a Comment »

ACTIVE SCAFFOLD

Posted by Bhushan G Ahire on August 16, 2007

Yet another featehr in the cap

RUBY ON RAILS

ACTIVE SCAFFOLD

i WOnt mention much as the deytailing would be long

just go through some links and i beleive you wont face any problem whatsoever….
well i hope every ruby on rails developer must have heard about rails scaffold
active scaffold does the same thing alos it does a few bit of more things
like ordering
searching the databse
ajaxed create edit delete dhow
and a loads of others wjhich normal scaffolding was incompatible to do

LINKS for active scaffold

http://wiki.activescaffold.com/wiki/show/Active+Scaffold+Upload+Branch

http://activescaffold.com/

http://demo.activescaffold.com/users

http://www.ajaxscaffold.com/#widget:1:null:asc

http://ajaxscaffold.stikipad.com/doc/

here goes nothing
commnet if you interafe with some problem
thanku

Posted in active scaffold, ajax scaffold, new, rails, ruby, ruby on rails, scaffold | Leave a Comment »

Improve Performance of Rails application using Yslow

Posted by Bhushan G Ahire on August 13, 2007

Yslow is the Firefox Plugin that gives details about the componnet in the webpages of application and some recommedation and tips to improve its performance.

check out this link for some tips to impreove performance using yslow:

http://www.slashdotdash.net/articles/2007/07/31/rails-performance-tip-using-yslow.

To download Yslow for Firefox go through this link :

https://addons.mozilla.org/en-US/firefox/addon/5369.

Posted in Uncategorized | Leave a Comment »

 
Follow

Get every new post delivered to your Inbox.