SlideShare a Scribd company logo
1 of 91
Page Caching Resurrected

Ben Sco eld – Viget Labs
Page Caching Resurrected:
A Fairy Tale
Ben Sco eld – Viget Labs
three little pigs
three little pigs
page caching
class PigsController
 caches_page :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_page :action => :show
 end
end
class PigsController
 caches_page :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_page :action => :show
 end
end
class PigsController
 caches_page :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_page :action => :show
 end
end
standard   1




   page    3000




                  requests per second
public
dynamic
content
action caching
class PigsController
 require_login :show
 caches_action :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_action :action => :show
 end
end
class PigsController
 require_login :show
 caches_action :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_action :action => :show
 end
end
class PigsController
 require_login :show
 caches_action :show

 def show
  @pig = Pig.find(params[:id])
 end

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_action :action => :show
 end
end
standard   1



  action   500



   page    3000




                  requests per second
dynamic
content
fragment caching
<% cache(:key => 'index:piglist') do %>
 <ul id=quot;pig-listquot;>
  <% @pigs.each do |pig| %>
   <li>
     <%= image_tag pig.house.photo %>
     <%= h pig.name %>
   </li>
  <% end %>
 </ul>
<% end %>
<% cache(:key => 'index:piglist') do %>
 <ul id=quot;pig-listquot;>
  <% @pigs.each do |pig| %>
   <li>
     <%= image_tag pig.house.photo %>
     <%= h pig.name %>
   </li>
  <% end %>
 </ul>
<% end %>
class PigsController
 # ...

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_fragment :key => 'index:piglist'
 end
end
class PigsController
 # ...

 def update
  @pig = Pig.find(params[:id])
  @pig.update_attributes(params[:pig])

  expire_fragment :key => 'index:piglist'
 end
end
standard   1


fragment   20


  action   500


   page    3000




                  requests per second
eficiency
the idea
Rails 2.3
hello, metal
class BigBadWolf
 def self.call(env)
   if env[quot;PATH_INFOquot;] =~ /^/threaten/
     [
       200,
       {quot;Content-Typequot; = quot;text/htmlquot;},
       quot;Little pig, little pig, let me in!quot;
     ]
   else
     [
       404,
       {quot;Content-Typequot; = quot;text/htmlquot;},
       quot;Not Foundquot;
     ]
   end
 end
end
high-performance endpoints
AJAX
so...
javascript
ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li class=quot;first sign-out-linkquot;
  a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot;
     onclick=quot;Login.show($('top-login-form')); return false;quot;Login/a
 /li
 li class=quot;signin-border-leftquot;
  a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;Forgot Password?/a
 /li
 li class=quot;signin-border-leftquot;
  a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a
 /li
/ul
div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot;
 form action=quot;https://secure.hulu.com/account/authenticatequot;
   method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot;
  span class=quot;login-statusquot;/span
  input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot;
   style=quot;display: none;quot; name=quot;usernamequot;/
  input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot;
   style=quot;display: none;quot; name=quot;passwordquot;/
  input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot;
   name=quot;dummy_loginquot; /
  input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; /
  input alt=quot;Loginquot; class=quot;login-submitquot;
   src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot;
   style=quot;width: 39px; height: 20;quot; type=quot;imagequot; /
  a href=quot;#quot;img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot;
   id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot;
   src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; //a
 /form

 a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a
/div
ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li id=quot;welcome-usernamequot; class=quot;firstquot;
  Welcome
 /li

 li
  a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a
 /li

 li
  a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a
 /li

 li class=quot;sign-out-linkquot;
  a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a
 /li
/ul
noscript
 ul class=quot;nojs usernavquot;
  li
   Please a href=quot;/support/quot;enable javascript/a to log in.
  /li
 /ul
/noscript
script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/
 Event.observe(window, quot;loadquot;, function() {
   Behaviors.onLoad();
   Behaviors.setLoggedIn();
   Login.setup();
   if ($(quot;loginquot;)  $(quot;login-formquot;)) {
     Event.observe('login', 'keydown', function(ev) {
       if (ev.keyCode == 13) { Login.submit(); }
     });
   }
 });
 Login.auth = function(login, password) {
   document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
   document.cookie = 'password=' + password + '; path=/account/authenticate; ...
   el = $$('body').first();
   if (el) {
     var script = document.createElement('script');
     script.type = 'text/javascript';
     script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
     el.appendChild(script);
   }
 }
/*]]*//script
ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li id=quot;welcome-usernamequot; class=quot;firstquot;
  Welcome
 /li

 li
  a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a
 /li

 li
  a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a
 /li

 li class=quot;sign-out-linkquot;
  a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a
 /li
/ul
ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot;
 li id=quot;welcome-usernamequot; class=quot;firstquot;
  Welcome
 /li

 li
  a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a
 /li

 li
  a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a
 /li

 li class=quot;sign-out-linkquot;
  a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a
 /li
/ul
hulu is insane
 don’t do it like they do
script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/
 Event.observe(window, quot;loadquot;, function() {
   Behaviors.onLoad();
   Behaviors.setLoggedIn();
   Login.setup();
   if ($(quot;loginquot;)  $(quot;login-formquot;)) {
     Event.observe('login', 'keydown', function(ev) {
       if (ev.keyCode == 13) { Login.submit(); }
     });
   }
 });
 Login.auth = function(login, password) {
   document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
   document.cookie = 'password=' + password + '; path=/account/authenticate; ...
   el = $$('body').first();
   if (el) {
     var script = document.createElement('script');
     script.type = 'text/javascript';
     script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
     el.appendChild(script);
   }
 }
/*]]*//script
script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/
 Event.observe(window, quot;loadquot;, function() {
   Behaviors.onLoad();
   Behaviors.setLoggedIn();
   Login.setup();
   if ($(quot;loginquot;)  $(quot;login-formquot;)) {
     Event.observe('login', 'keydown', function(ev) {
       if (ev.keyCode == 13) { Login.submit(); }
     });
   }
 });
 Login.auth = function(login, password) {
   document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ...
   document.cookie = 'password=' + password + '; path=/account/authenticate; ...
   el = $$('body').first();
   if (el) {
     var script = document.createElement('script');
     script.type = 'text/javascript';
     script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ...
     el.appendChild(script);
   }
 }
/*]]*//script
the* right way


      *a
the standard approach
class ItemsController  ApplicationController
 def index
   @user = User.find_by_login(params[:user])
   @items = Item.released_on(params[:date])
 end
end
class Item  ActiveRecord::Base
 has_many :pulls, :dependent = :destroy

 named_scope :released_on, lambda { |date|
   date ||= Item.maximum(:released_on)
   {:conditions = {:released_on = date}, :order = 'name ASC'}
 }

 def pulled_by?(user)
  x = user.nil? ? false : !self.pulls.by_user(user.id).empty?
 end
end
h1Releases/h1

ul
 % @items.each do |item| %
  % content_tag_for :li, item do %
   %= image_tag 'cover.png', :alt = h(item.name), :class = 'cover' %
   %= image_tag('badge.png', :alt = 'pulling',:class = 'badge')
      if item.pulled_by?(@user) %
   p%= h item.name %/p
  % end %
 % end %
/ul
the hybrid approach
class ItemsController  ApplicationController
 caches_page :index

 def index
  @items = Item.released_on(params[:date]).all
 end
end
require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless
 defined?(Rails)

class PullList
 def self.call(env)
   if env[quot;PATH_INFOquot;] =~ /^/pulls/
     date = '2008-11-05'
     user = '1'
     [
       200,
      {quot;Content-Typequot; = quot;application/javascriptquot;},
      [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]]
   else
     [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]]
   end
 end
end
class Pull  ActiveRecord::Base
 belongs_to :user
 belongs_to :item

 named_scope :by_user, lambda { |user_id|
   {:conditions = {:user_id = user_id}}
 }
 named_scope :for_date, lambda { |date|
   {:include = :item, :conditions = {:items = {:released_on = date}}}
 }
end
$(document).ready(function() {
  $.getJSON('/pulls', function(data) {
    $.each(data, function() {
      $('#item_'+this).addClass('pulled');
    });
  });
});
standard
hybrid
standard   0.617




  hybrid   0.039 0.096




                         content load time
hybrid approach - version 2
class SessionsController  ApplicationController
 def new; end

 def create
  # ...
  session[:pulls] = @user.pulls.map {|i| i.item_id}
  redirect_to items_path
 end
end
require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless
 defined?(Rails)

class PullList
 def self.call(env)
   if env[quot;PATH_INFOquot;] =~ /^/pulls/
     date = '2008-11-05'
     user = '1'
     [
       200,
       {quot;Content-Typequot; = quot;application/javascriptquot;},
       [env['rack.session'][:pulls].to_json]
     ]
   else
     [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]]
   end
 end
end
hybrid v2
standard    0.617



  hybrid    0.039 0.096



hybrid v2   0.043 0.023




                          content load time
when to use it
when not to use it
accessibility
accessibility
noscript
 ul class=quot;nojs usernavquot;
  li
   Please a href=quot;/support/quot;enable javascript/a to log in.
  /li
 /ul
/noscript
Thank You
ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld

More Related Content

What's hot

Plone Interactivity
Plone InteractivityPlone Interactivity
Plone InteractivityEric Steele
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワークTakatsugu Shigeta
 
Web Security Mistakes: Trusting The Client
Web Security Mistakes: Trusting The ClientWeb Security Mistakes: Trusting The Client
Web Security Mistakes: Trusting The Clientgrutz
 
Rails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity PresentationRails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity Presentationrailsconf
 
IBM Lotus Notes Domino XPages and XPages for Mobile
IBM Lotus Notes Domino XPages and XPages for MobileIBM Lotus Notes Domino XPages and XPages for Mobile
IBM Lotus Notes Domino XPages and XPages for MobileChris Toohey
 
Your Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages SuckYour Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages SuckAnthony Montalbano
 
网站无障碍阅读知识
网站无障碍阅读知识网站无障碍阅读知识
网站无障碍阅读知识ppanyong
 
Presentasi Kelompok 25 PW A+B
Presentasi Kelompok 25 PW A+BPresentasi Kelompok 25 PW A+B
Presentasi Kelompok 25 PW A+BHapsoro Permana
 
Tugas pw [kelompok 25]
Tugas pw [kelompok 25]Tugas pw [kelompok 25]
Tugas pw [kelompok 25]guest0ad6a0
 
Make Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingMake Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingViget Labs
 
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]Chris Toohey
 
The project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicerThe project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicerAndrei Hortúa
 

What's hot (20)

Plone Interactivity
Plone InteractivityPlone Interactivity
Plone Interactivity
 
シックス・アパート・フレームワーク
シックス・アパート・フレームワークシックス・アパート・フレームワーク
シックス・アパート・フレームワーク
 
Web Security Mistakes: Trusting The Client
Web Security Mistakes: Trusting The ClientWeb Security Mistakes: Trusting The Client
Web Security Mistakes: Trusting The Client
 
Rails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity PresentationRails 3 And The Real Secret To High Productivity Presentation
Rails 3 And The Real Secret To High Productivity Presentation
 
Stole16
Stole16Stole16
Stole16
 
IBM Lotus Notes Domino XPages and XPages for Mobile
IBM Lotus Notes Domino XPages and XPages for MobileIBM Lotus Notes Domino XPages and XPages for Mobile
IBM Lotus Notes Domino XPages and XPages for Mobile
 
DevDays09 Internet Explorer 8
DevDays09 Internet Explorer 8DevDays09 Internet Explorer 8
DevDays09 Internet Explorer 8
 
Fast by Default
Fast by DefaultFast by Default
Fast by Default
 
Your Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages SuckYour Custom WordPress Admin Pages Suck
Your Custom WordPress Admin Pages Suck
 
Spring 2.0
Spring 2.0Spring 2.0
Spring 2.0
 
网站无障碍阅读知识
网站无障碍阅读知识网站无障碍阅读知识
网站无障碍阅读知识
 
Presentasi Kelompok 25 PW A+B
Presentasi Kelompok 25 PW A+BPresentasi Kelompok 25 PW A+B
Presentasi Kelompok 25 PW A+B
 
SlideShare Instant
SlideShare InstantSlideShare Instant
SlideShare Instant
 
Tugas pw [kelompok 25]
Tugas pw [kelompok 25]Tugas pw [kelompok 25]
Tugas pw [kelompok 25]
 
SlideShare Instant
SlideShare InstantSlideShare Instant
SlideShare Instant
 
Spring 2.0
Spring 2.0Spring 2.0
Spring 2.0
 
Make Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance TestingMake Everyone a Tester: Natural Language Acceptance Testing
Make Everyone a Tester: Natural Language Acceptance Testing
 
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
10 Things You're Not Doing [IBM Lotus Notes Domino Application Development]
 
The project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicerThe project gutenberg e book, fairy tales from brazil, by elsie spicer
The project gutenberg e book, fairy tales from brazil, by elsie spicer
 
spring_jiaocheng
spring_jiaochengspring_jiaocheng
spring_jiaocheng
 

Viewers also liked

Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsBen Scofield
 
Cleanliness is Next to Domain-Specificity
Cleanliness is Next to Domain-SpecificityCleanliness is Next to Domain-Specificity
Cleanliness is Next to Domain-SpecificityBen Scofield
 
Resourceful Plugins
Resourceful PluginsResourceful Plugins
Resourceful PluginsBen Scofield
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUGBen Scofield
 
How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsBen Scofield
 

Viewers also liked (6)

Ciclo 13
Ciclo 13Ciclo 13
Ciclo 13
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Cleanliness is Next to Domain-Specificity
Cleanliness is Next to Domain-SpecificityCleanliness is Next to Domain-Specificity
Cleanliness is Next to Domain-Specificity
 
Resourceful Plugins
Resourceful PluginsResourceful Plugins
Resourceful Plugins
 
Building Cloud Castles - LRUG
Building Cloud Castles - LRUGBuilding Cloud Castles - LRUG
Building Cloud Castles - LRUG
 
How to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 StepsHow to Be Awesome in 2.5 Steps
How to Be Awesome in 2.5 Steps
 

Similar to Page Caching Resurrected

Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On RailsWen-Tien Chang
 
Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008Rob
 
Pluginが広げるRailsの魅力
Pluginが広げるRailsの魅力Pluginが広げるRailsの魅力
Pluginが広げるRailsの魅力Yoji Shidara
 
Ajax On S2 Odp
Ajax On S2 OdpAjax On S2 Odp
Ajax On S2 Odpghessler
 
Django - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosDjango - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosIgor Sobreira
 
Couch Db.0.9.0.Pub
Couch Db.0.9.0.PubCouch Db.0.9.0.Pub
Couch Db.0.9.0.PubYohei Sasaki
 
Haml & Sass presentation
Haml & Sass presentationHaml & Sass presentation
Haml & Sass presentationbryanbibat
 
Microsoft ASP.NET 4.0 : What's Next?
Microsoft ASP.NET 4.0 : What's Next?Microsoft ASP.NET 4.0 : What's Next?
Microsoft ASP.NET 4.0 : What's Next?goodfriday
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialYi-Ting Cheng
 
Struts2
Struts2Struts2
Struts2yuvalb
 
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010Sergey Ilinsky
 

Similar to Page Caching Resurrected (20)

Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
 
Front End on Rails
Front End on RailsFront End on Rails
Front End on Rails
 
Merb jQuery
Merb jQueryMerb jQuery
Merb jQuery
 
Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008Rugalytics | Ruby Manor Nov 2008
Rugalytics | Ruby Manor Nov 2008
 
Ajax
AjaxAjax
Ajax
 
Pluginが広げるRailsの魅力
Pluginが広げるRailsの魅力Pluginが広げるRailsの魅力
Pluginが広げるRailsの魅力
 
Ajax On S2 Odp
Ajax On S2 OdpAjax On S2 Odp
Ajax On S2 Odp
 
Ajax ons2
Ajax ons2Ajax ons2
Ajax ons2
 
Javascript Basic
Javascript BasicJavascript Basic
Javascript Basic
 
A rel
A relA rel
A rel
 
Seam Glassfish Slidecast
Seam Glassfish SlidecastSeam Glassfish Slidecast
Seam Glassfish Slidecast
 
JSP Custom Tags
JSP Custom TagsJSP Custom Tags
JSP Custom Tags
 
Widgets Tools Keynote
Widgets Tools KeynoteWidgets Tools Keynote
Widgets Tools Keynote
 
Django - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazosDjango - Framework web para perfeccionistas com prazos
Django - Framework web para perfeccionistas com prazos
 
Couch Db.0.9.0.Pub
Couch Db.0.9.0.PubCouch Db.0.9.0.Pub
Couch Db.0.9.0.Pub
 
Haml & Sass presentation
Haml & Sass presentationHaml & Sass presentation
Haml & Sass presentation
 
Microsoft ASP.NET 4.0 : What's Next?
Microsoft ASP.NET 4.0 : What's Next?Microsoft ASP.NET 4.0 : What's Next?
Microsoft ASP.NET 4.0 : What's Next?
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Struts2
Struts2Struts2
Struts2
 
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
Building Complex GUI Apps The Right Way. With Ample SDK - SWDC2010
 

More from Ben Scofield

Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers StealBen Scofield
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to ArmsBen Scofield
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud CastlesBen Scofield
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and MasteryBen Scofield
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or MediocrityBen Scofield
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty HammerBen Scofield
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation AtlantaBen Scofield
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding MasteryBen Scofield
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the WebBen Scofield
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQLBen Scofield
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010Ben Scofield
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)Ben Scofield
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardBen Scofield
 
The Future of Data
The Future of DataThe Future of Data
The Future of DataBen Scofield
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardBen Scofield
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative DatabasesBen Scofield
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the WebBen Scofield
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the EarthBen Scofield
 

More from Ben Scofield (20)

Great Developers Steal
Great Developers StealGreat Developers Steal
Great Developers Steal
 
Thinking Small
Thinking SmallThinking Small
Thinking Small
 
Open Source: A Call to Arms
Open Source: A Call to ArmsOpen Source: A Call to Arms
Open Source: A Call to Arms
 
Ship It
Ship ItShip It
Ship It
 
Building Cloud Castles
Building Cloud CastlesBuilding Cloud Castles
Building Cloud Castles
 
Intentionality: Choice and Mastery
Intentionality: Choice and MasteryIntentionality: Choice and Mastery
Intentionality: Choice and Mastery
 
Mastery or Mediocrity
Mastery or MediocrityMastery or Mediocrity
Mastery or Mediocrity
 
With a Mighty Hammer
With a Mighty HammerWith a Mighty Hammer
With a Mighty Hammer
 
Mind Control - DevNation Atlanta
Mind Control - DevNation AtlantaMind Control - DevNation Atlanta
Mind Control - DevNation Atlanta
 
Understanding Mastery
Understanding MasteryUnderstanding Mastery
Understanding Mastery
 
Mind Control: Psychology for the Web
Mind Control: Psychology for the WebMind Control: Psychology for the Web
Mind Control: Psychology for the Web
 
The State of NoSQL
The State of NoSQLThe State of NoSQL
The State of NoSQL
 
NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010NoSQL @ CodeMash 2010
NoSQL @ CodeMash 2010
 
NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)NoSQL: Death to Relational Databases(?)
NoSQL: Death to Relational Databases(?)
 
Charlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is HardCharlotte.rb - "Comics" Is Hard
Charlotte.rb - "Comics" Is Hard
 
The Future of Data
The Future of DataThe Future of Data
The Future of Data
 
WindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is HardWindyCityRails - "Comics" Is Hard
WindyCityRails - "Comics" Is Hard
 
"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases"Comics" Is Hard: Alternative Databases
"Comics" Is Hard: Alternative Databases
 
Mind Control on the Web
Mind Control on the WebMind Control on the Web
Mind Control on the Web
 
How the Geeks Inherited the Earth
How the Geeks Inherited the EarthHow the Geeks Inherited the Earth
How the Geeks Inherited the Earth
 

Recently uploaded

Best VIP Call Girls Noida Sector 18 Call Me: 8264348440
Best VIP Call Girls Noida Sector 18 Call Me: 8264348440Best VIP Call Girls Noida Sector 18 Call Me: 8264348440
Best VIP Call Girls Noida Sector 18 Call Me: 8264348440soniya singh
 
Call Girls In Lajpat Nagar__ 8448079011 __Escort Service In Delhi
Call Girls In Lajpat Nagar__ 8448079011 __Escort Service In DelhiCall Girls In Lajpat Nagar__ 8448079011 __Escort Service In Delhi
Call Girls In Lajpat Nagar__ 8448079011 __Escort Service In DelhiRaviSingh594208
 
Independent Call Girls Delhi ~9711199012~ Call Me
Independent Call Girls Delhi ~9711199012~ Call MeIndependent Call Girls Delhi ~9711199012~ Call Me
Independent Call Girls Delhi ~9711199012~ Call MeMs Riya
 
Call Girls In Goa 7028418221 Call Girls In Colva Beach Escorts Service
Call Girls In Goa 7028418221 Call Girls In Colva Beach Escorts ServiceCall Girls In Goa 7028418221 Call Girls In Colva Beach Escorts Service
Call Girls In Goa 7028418221 Call Girls In Colva Beach Escorts ServiceApsara Of India
 
Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -
Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -
Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -Pooja Nehwal
 
꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call
꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call
꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip CallMs Riya
 
Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
AliExpress Clothing Brand Media Planning
AliExpress Clothing Brand Media PlanningAliExpress Clothing Brand Media Planning
AliExpress Clothing Brand Media Planningjen_giacalone
 
Youthlab Indonesia Gen-Z Lifestyle Chart
Youthlab Indonesia Gen-Z Lifestyle ChartYouthlab Indonesia Gen-Z Lifestyle Chart
Youthlab Indonesia Gen-Z Lifestyle ChartYouthLab
 
Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝soniya singh
 
Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...
Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...
Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...Pooja Nehwal
 
A TO Z INDIA Monthly Magazine - MAY 2024
A TO Z INDIA Monthly Magazine - MAY 2024A TO Z INDIA Monthly Magazine - MAY 2024
A TO Z INDIA Monthly Magazine - MAY 2024Indira Srivatsa
 
Dubai Call Girls O528786472 Call Girls Dubai OL
Dubai Call Girls O528786472 Call Girls Dubai OLDubai Call Girls O528786472 Call Girls Dubai OL
Dubai Call Girls O528786472 Call Girls Dubai OLhf8803863
 
Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...
Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...
Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...hf8803863
 
Neelam 9058824046 Call Girls Service in Haridwar
Neelam 9058824046 Call Girls Service in HaridwarNeelam 9058824046 Call Girls Service in Haridwar
Neelam 9058824046 Call Girls Service in Haridwarjaanseema653
 
10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway
10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway
10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar HealthywayAmit Kakkar Healthyway
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | Delhisoniya singh
 
Call Girls In Karol Bagh__ 8448079011 Escort Service in Delhi
Call Girls In Karol Bagh__ 8448079011 Escort Service in DelhiCall Girls In Karol Bagh__ 8448079011 Escort Service in Delhi
Call Girls In Karol Bagh__ 8448079011 Escort Service in DelhiRaviSingh594208
 
Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝soniya singh
 

Recently uploaded (20)

Best VIP Call Girls Noida Sector 18 Call Me: 8264348440
Best VIP Call Girls Noida Sector 18 Call Me: 8264348440Best VIP Call Girls Noida Sector 18 Call Me: 8264348440
Best VIP Call Girls Noida Sector 18 Call Me: 8264348440
 
Call Girls In Lajpat Nagar__ 8448079011 __Escort Service In Delhi
Call Girls In Lajpat Nagar__ 8448079011 __Escort Service In DelhiCall Girls In Lajpat Nagar__ 8448079011 __Escort Service In Delhi
Call Girls In Lajpat Nagar__ 8448079011 __Escort Service In Delhi
 
Independent Call Girls Delhi ~9711199012~ Call Me
Independent Call Girls Delhi ~9711199012~ Call MeIndependent Call Girls Delhi ~9711199012~ Call Me
Independent Call Girls Delhi ~9711199012~ Call Me
 
Call Girls In Goa 7028418221 Call Girls In Colva Beach Escorts Service
Call Girls In Goa 7028418221 Call Girls In Colva Beach Escorts ServiceCall Girls In Goa 7028418221 Call Girls In Colva Beach Escorts Service
Call Girls In Goa 7028418221 Call Girls In Colva Beach Escorts Service
 
Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -
Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -
Mumbai Call Girls Malad West WhatsApp 9892124323 Full Night Enjoy -
 
꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call
꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call
꧁❤ Greater Noida Call Girls Delhi ❤꧂ 9711199012 ☎️ Hard And Sexy Vip Call
 
Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝
Call Girls in New Friends Colony Delhi 💯Call Us 🔝8264348440🔝
 
AliExpress Clothing Brand Media Planning
AliExpress Clothing Brand Media PlanningAliExpress Clothing Brand Media Planning
AliExpress Clothing Brand Media Planning
 
Youthlab Indonesia Gen-Z Lifestyle Chart
Youthlab Indonesia Gen-Z Lifestyle ChartYouthlab Indonesia Gen-Z Lifestyle Chart
Youthlab Indonesia Gen-Z Lifestyle Chart
 
Russian Call Girls Rohini Sector 25 💓 Delhi 9999965857 @Sabina Modi VVIP MODE...
Russian Call Girls Rohini Sector 25 💓 Delhi 9999965857 @Sabina Modi VVIP MODE...Russian Call Girls Rohini Sector 25 💓 Delhi 9999965857 @Sabina Modi VVIP MODE...
Russian Call Girls Rohini Sector 25 💓 Delhi 9999965857 @Sabina Modi VVIP MODE...
 
Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝
Call Girls in Chittaranjan Park Delhi 💯Call Us 🔝8264348440🔝
 
Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...
Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...
Call Numbe 9892124323, Vashi call girls, Juhu Call Girls, Powai Call Girls Se...
 
A TO Z INDIA Monthly Magazine - MAY 2024
A TO Z INDIA Monthly Magazine - MAY 2024A TO Z INDIA Monthly Magazine - MAY 2024
A TO Z INDIA Monthly Magazine - MAY 2024
 
Dubai Call Girls O528786472 Call Girls Dubai OL
Dubai Call Girls O528786472 Call Girls Dubai OLDubai Call Girls O528786472 Call Girls Dubai OL
Dubai Call Girls O528786472 Call Girls Dubai OL
 
Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...
Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...
Jumeirah Call Girls Dubai Concupis O528786472 Dubai Call Girls In Bur Dubai N...
 
Neelam 9058824046 Call Girls Service in Haridwar
Neelam 9058824046 Call Girls Service in HaridwarNeelam 9058824046 Call Girls Service in Haridwar
Neelam 9058824046 Call Girls Service in Haridwar
 
10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway
10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway
10 Tips To Be More Disciplined In Life To Be Successful | Amit Kakkar Healthyway
 
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | DelhiFULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | Delhi
FULL ENJOY 🔝 8264348440 🔝 Call Girls in Jama Masjid | Delhi
 
Call Girls In Karol Bagh__ 8448079011 Escort Service in Delhi
Call Girls In Karol Bagh__ 8448079011 Escort Service in DelhiCall Girls In Karol Bagh__ 8448079011 Escort Service in Delhi
Call Girls In Karol Bagh__ 8448079011 Escort Service in Delhi
 
Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝
Model Call Girl in Adarsh Nagar Delhi reach out to us at 🔝8264348440🔝
 

Page Caching Resurrected

  • 1. Page Caching Resurrected Ben Sco eld – Viget Labs
  • 2. Page Caching Resurrected: A Fairy Tale Ben Sco eld – Viget Labs
  • 3.
  • 7.
  • 8.
  • 9. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end
  • 10. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end
  • 11. class PigsController caches_page :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_page :action => :show end end
  • 12. standard 1 page 3000 requests per second
  • 15.
  • 16.
  • 17. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end
  • 18. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end
  • 19. class PigsController require_login :show caches_action :show def show @pig = Pig.find(params[:id]) end def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_action :action => :show end end
  • 20. standard 1 action 500 page 3000 requests per second
  • 23.
  • 24.
  • 25. <% cache(:key => 'index:piglist') do %> <ul id=quot;pig-listquot;> <% @pigs.each do |pig| %> <li> <%= image_tag pig.house.photo %> <%= h pig.name %> </li> <% end %> </ul> <% end %>
  • 26. <% cache(:key => 'index:piglist') do %> <ul id=quot;pig-listquot;> <% @pigs.each do |pig| %> <li> <%= image_tag pig.house.photo %> <%= h pig.name %> </li> <% end %> </ul> <% end %>
  • 27. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end
  • 28. class PigsController # ... def update @pig = Pig.find(params[:id]) @pig.update_attributes(params[:pig]) expire_fragment :key => 'index:piglist' end end
  • 29. standard 1 fragment 20 action 500 page 3000 requests per second
  • 34. class BigBadWolf def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/threaten/ [ 200, {quot;Content-Typequot; = quot;text/htmlquot;}, quot;Little pig, little pig, let me in!quot; ] else [ 404, {quot;Content-Typequot; = quot;text/htmlquot;}, quot;Not Foundquot; ] end end end
  • 36. AJAX
  • 37. so...
  • 39.
  • 40.
  • 41.
  • 42.
  • 43.
  • 44.
  • 45.
  • 46. ul id=quot;logged-out-navquot; class=quot;usernavquot; style=quot;display:nonequot; li class=quot;first sign-out-linkquot; a class=quot;utility-linkquot; href=quot;#quot; id=quot;login-linkquot; onclick=quot;Login.show($('top-login-form')); return false;quot;Login/a /li li class=quot;signin-border-leftquot; a href=quot;/users/forgot_passwordquot; class=quot;utility-linkquot;Forgot Password?/a /li li class=quot;signin-border-leftquot; a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a /li /ul
  • 47. div id=quot;top-login-formquot; class=quot;usernav login-formquot; style=quot;display:nonequot; form action=quot;https://secure.hulu.com/account/authenticatequot; method=quot;getquot; name=quot;login-formquot; onsubmit=quot;Login.submit(this); return false;quot; span class=quot;login-statusquot;/span input id=quot;loginquot; class=quot;active loginquot; type=quot;textquot; style=quot;display: none;quot; name=quot;usernamequot;/ input id=quot;passwordquot; class=quot;active passwordquot; type=quot;passwordquot; style=quot;display: none;quot; name=quot;passwordquot;/ input class=quot;inactive dummy loginquot; type=quot;textquot; value=quot;usernamequot; name=quot;dummy_loginquot; / input class=quot;inactive dummyquot; type=quot;textquot; value=quot;passwordquot; name=quot;dummy_passwordquot; / input alt=quot;Loginquot; class=quot;login-submitquot; src=quot;http://static.hulu.com/images/btn-signin-small.gif?1237361096quot; style=quot;width: 39px; height: 20;quot; type=quot;imagequot; / a href=quot;#quot;img alt=quot;Cancelquot; border=quot;0quot; class=quot;hover-mequot; height=quot;20quot; id=quot;btn-x.gif123741536309506quot; onclick=quot;Login.cancel();return falsequot; src=quot;http://static.hulu.com/images/btn-x.gif?1237361096quot; width=quot;18quot; //a /form a href=quot;/signupquot; class=quot;utility-linkquot;Sign Up/a /div
  • 48. ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot; li id=quot;welcome-usernamequot; class=quot;firstquot; Welcome /li li a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a /li li a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a /li li class=quot;sign-out-linkquot; a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a /li /ul
  • 49. noscript ul class=quot;nojs usernavquot; li Please a href=quot;/support/quot;enable javascript/a to log in. /li /ul /noscript
  • 50. script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]*//script
  • 51. ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot; li id=quot;welcome-usernamequot; class=quot;firstquot; Welcome /li li a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a /li li a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a /li li class=quot;sign-out-linkquot; a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a /li /ul
  • 52. ul id=quot;logged-in-navquot; class=quot;usernavquot; style=quot;display:nonequot; li id=quot;welcome-usernamequot; class=quot;firstquot; Welcome /li li a href=quot;/profilequot; class=quot;utility-linkquot;Profile/a /li li a href=quot;/profile/queuequot; class=quot;utility-linkquot; id=quot;your-queue-linkquot;Queue/a /li li class=quot;sign-out-linkquot; a href=quot;#quot; id=quot;top-nav-sign-outquot; onclick=quot;new Ajax.Request(...)quot;Sign Out/a /li /ul
  • 53.
  • 54. hulu is insane don’t do it like they do
  • 55. script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]*//script
  • 56. script type=quot;text/javascriptquot; charset=quot;utf-8quot;/*![CDATA[*/ Event.observe(window, quot;loadquot;, function() { Behaviors.onLoad(); Behaviors.setLoggedIn(); Login.setup(); if ($(quot;loginquot;) $(quot;login-formquot;)) { Event.observe('login', 'keydown', function(ev) { if (ev.keyCode == 13) { Login.submit(); } }); } }); Login.auth = function(login, password) { document.cookie = 'login=' + login + '; path=/account/authenticate; secure; ... document.cookie = 'password=' + password + '; path=/account/authenticate; ... el = $$('body').first(); if (el) { var script = document.createElement('script'); script.type = 'text/javascript'; script.src = quot;https://secure.hulu.com/account/authenticatequot; + '?' + ... el.appendChild(script); } } /*]]*//script
  • 58.
  • 59.
  • 60.
  • 62. class ItemsController ApplicationController def index @user = User.find_by_login(params[:user]) @items = Item.released_on(params[:date]) end end
  • 63. class Item ActiveRecord::Base has_many :pulls, :dependent = :destroy named_scope :released_on, lambda { |date| date ||= Item.maximum(:released_on) {:conditions = {:released_on = date}, :order = 'name ASC'} } def pulled_by?(user) x = user.nil? ? false : !self.pulls.by_user(user.id).empty? end end
  • 64. h1Releases/h1 ul % @items.each do |item| % % content_tag_for :li, item do % %= image_tag 'cover.png', :alt = h(item.name), :class = 'cover' % %= image_tag('badge.png', :alt = 'pulling',:class = 'badge') if item.pulled_by?(@user) % p%= h item.name %/p % end % % end % /ul
  • 65.
  • 67. class ItemsController ApplicationController caches_page :index def index @items = Item.released_on(params[:date]).all end end
  • 68. require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless defined?(Rails) class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ date = '2008-11-05' user = '1' [ 200, {quot;Content-Typequot; = quot;application/javascriptquot;}, [Pull.by_user(user).for_date(date).map {|i| i.item_id}.to_json]] else [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end
  • 69. class Pull ActiveRecord::Base belongs_to :user belongs_to :item named_scope :by_user, lambda { |user_id| {:conditions = {:user_id = user_id}} } named_scope :for_date, lambda { |date| {:include = :item, :conditions = {:items = {:released_on = date}}} } end
  • 70. $(document).ready(function() { $.getJSON('/pulls', function(data) { $.each(data, function() { $('#item_'+this).addClass('pulled'); }); }); });
  • 73. standard 0.617 hybrid 0.039 0.096 content load time
  • 74. hybrid approach - version 2
  • 75. class SessionsController ApplicationController def new; end def create # ... session[:pulls] = @user.pulls.map {|i| i.item_id} redirect_to items_path end end
  • 76. require(File.dirname(__FILE__) + quot;/../../config/environmentquot;) unless defined?(Rails) class PullList def self.call(env) if env[quot;PATH_INFOquot;] =~ /^/pulls/ date = '2008-11-05' user = '1' [ 200, {quot;Content-Typequot; = quot;application/javascriptquot;}, [env['rack.session'][:pulls].to_json] ] else [404, {quot;Content-Typequot; = quot;text/htmlquot;}, [quot;Not Foundquot;]] end end end
  • 78. standard 0.617 hybrid 0.039 0.096 hybrid v2 0.043 0.023 content load time
  • 80.
  • 81.
  • 82.
  • 83.
  • 84.
  • 85.
  • 86. when not to use it
  • 87.
  • 90. noscript ul class=quot;nojs usernavquot; li Please a href=quot;/support/quot;enable javascript/a to log in. /li /ul /noscript
  • 91. Thank You ben sco eld - @bsco eld - http://www.viget.com/extend - http://www.speakerrate.com/bsco eld

Editor's Notes

  1. super simple to use, but results in PUBLIC content
  2. super simple to use, but results in PUBLIC content
  3. more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available
  4. more framework-specific; solves auth-protected pages, etc. - cached content is not publicly available
  5. caches only specific parts of the page, which are not publically available
  6. expiration of each fragment, individually
  7. 10 minutes
  8. 15 minutes
  9. 22 minutes
  10. 26 minutes
  11. 135ms for hybrid, which is 21% of the standard lame tests I employed showed the same or greater effect
  12. 26 minutes
  13. 66ms for hybrid v2, 10.6% of standard and 48% of hybrid
  14. 34 minutes