SlideShare a Scribd company logo
1 of 54
Download to read offline
Forumwarz and RJS
A love/hate affair
An internet-based game
  about the internet
LOL WHUT?
The Internet is a
wonderful, magical place!
But it’s also terrible.
Very, very terrible.
John Gabriel’s Greater Internet Fuckwad Theory
Exhibit A
Have you heard of it?
• One of the most popular forums in the
  world
• Almost all its users are anonymous
• Unfortunately, it’s hilarious.
The anonymity of the
Internet means you can
     be anything...
You can be another ethnicity!
You can be another species!
You can even be beautiful!
(Even if you’re not.)
Are you going to explain
 what forumwarz is, or
 just show us hackneyed
 image macros all night?
Role-Play an Internet User!




 Camwhore   Emo Kid   Troll
Role-Play an Internet User!
  • Each player class features unique abilities
    and attacks
  • Many different ways to play
  • A detailed story line ties it all together
An interface heavy in RJS

    (please endure this short demo)
Let’s get technical
Forumwarz Technology
Some of our stats
• ~30,000 user accounts since we launched
  one month ago
• 2 million dynamic requests per day (25-55
  req/s)
• Static requests (images, stylesheets, js) are
  infrequent, since they’re set to expire in the
  far future
• About 25GB of bandwidth per day
Deployment
• Single server: 3.0Ghz quad-core Xeon, 3GB
  of RAM
• Nginx proxy to pack of 16 evented
  mongrels
• Modest-sized memcached daemon
Thank you AJAX!
• One reason we can handle so many
  requests off a single server is because
  they’re tiny
• We try to let the request get in and out as
  quickly as possible
• RJS makes writing Javascript ridiculously
  simple
why we   rjs
A simple example
Example View
 #battle_log
   There's a large monster in front of you.

 = link_to_remote quot;Attack Monster!quot;, :action => 'attack'




Example Controller
 def attack
   @monster = Monster.find(session[:current_monster_id])
   @player = Player.find(session[:current_player_id])

   @player.attack(@monster)

   update_page_tag do |page|
     page.insert_html :top, 'battle_log', :partial => 'attack_result'
   end
 end
Pretty cool eh?
• Without writing a line of javascript we’ve
  made a controller respond to an AJAX
  request
• It’s fast. No need to request a full page for
  such a small update
• It works great*
* but it can haunt you
Problem #1: Double Clicks
 • Often, people will click twice (or more!) in
   rapid succession
 • Your server gets two requests
 • If you’re lucky they will occur serially
A Solution?
• Use some javascript to prevent multiple
     clicks on the client side
 var ClickRegistry = {
   clicks : $H(),

     can_click_on : function(click_id) {
        return (this.clicks.get(click_id) == null)
     },
     clicked_on : function(click_id) {
        this.clicks.set(click_id, true)
     },
     done_call : function(click_id) {
        this.clicks.unset(click_id)
     }
 }
A Solution?
• Add a helper, link_once_remote
def link_once_remote(name, options = {}, html_options = {})

 click_id = html_options[:id] || Useful.unique_id
 options[:condition] = quot;ClickRegistry.can_click_on('#{click_id}')quot;

 prev_before = options[:before]
 options[:before] = quot;ClickRegistry.clicked_on('#{click_id}')quot;
 options[:before] << quot;; #{prev_before}quot; if prev_before

 prev_complete = options[:complete]
 options[:complete] = quot;ClickRegistry.done_call('#{click_id}')quot;
 options[:complete] << quot;; #{prev_complete}quot; if prev_complete

  link_to_remote(name, options, html_options)
end
Our Example: v.2
Example View
 #battle_log
   There's a large monster in front of you.

 = link_once_remote quot;Attack Monster!quot;, :action => 'attack'
Surprise!




It doesn’t work!
Why not?
• Proxies or download “accelerators”
• Browser add-ons might disagree with the
  javascript
Also, it’s client validated!
• Let’s face it: You can never, ever trust client
  validated data
• Even if the Javascript worked perfectly,
  people would create greasemonkey scripts
  or bots to exploit it
 • Our users have already been doing this :(
Server Side Validation
• It’s the Rails way
• If it fails, we can choose how to deal with
  the invalid request
  • Sometimes it makes sense to just ignore
    a request
  • Other times you might want to alert the
    user
Problem #2:Validations
• ActiveRecord validations can break during
  concurrency
• In particular, the validates_uniqueness_of
  validation
The Uniqueness Life-Cycle
  select * from battle_turns where turn = 1
  and user_id = 1;
  if no rows returned
     insert into battle_turns (...)
  else
     return errors collection
Transactions don’t help
• With default isolation levels, reads aren’t
  locked
• Assuming you have indexed the columns in
  your database you will get a DB error
• So much for reporting errors to the user
  nicely!
A solution?
• Could monkey patch ActiveRecord to lock
  the tables
• That’s fine if you don’t mind slowing your
  database to a crawl and a ridiculous amount
  of deadlocks
A different solution?
• You can rescue the DB error, and check to
  see if it’s a unique constraint that’s failing
• This is what we did. It works, but it ties you
  to a particular database
    def save_with_catching_duplicates(*args)
      begin
        return save_without_catching_duplicates(*args)
      rescue ActiveRecord::StatementInvalid => error
        if error.to_s.include?(quot;Mysql::Error: Duplicate entryquot;)
          # Do what you want with the error. In our case we raise a
          # custom exception that we catch and deal with how we want
        end
      end
    end

    alias_method_chain :save, :catching_duplicates
Problem #3: Animation
• script.aculo.us has some awesome
  animation effects, and we use them often.
• RJS gives you the great visual_effect helper
  method to do this:
  page.visual_effect :fade, 'toolbar'
  page.visual_effect :shake, 'score'
When order matters
• Often you’ll want to perform animation in
  order
• RJS executes visual effects in parallel
• There are two ways around this
Effect Queues
• You can queue together visual effects by
  assigning a name to a visual effect and a
  position in the queue.
• Works great when all you are doing is
  animating
• Does not work when you want to call
  custom Javascript at any point in the queue
• Unfortunately we do this, in particular to
  deal with our toolbar
page.delay
   page.visual_effect :fade, 'toolbar', :duration => 1.5
   page.delay(1.5) do
     page.call 'Toolbar.maintenance'
     page.visual_effect :shake, 'score'
   end




• Executes a block after a delay
• If paired with :duration, you can have the
  block execute after a certain amount of time
It’s me again!




This also doesn’t work!
Durations aren’t guaranteed
  • Your timing is at the whim of your client’s
    computer
  • Your effects can step on each other,
    preventing the animation from completing!
  • They will email you complaining that your
    app has “locked up”
A solution?
def visual_effect_with_callback_generation(name, id = false, options = {})
  options.each do |key,value|
    if value.is_a?(Proc)
      js = update_page(&value)
      options[key] = quot;function() { #{js} }quot;
    end
  end
  visual_effect_without_callback_generation(name, id, options)
end

alias_method_chain :visual_effect, :callback_generation




                                    Thanks to skidooer on the
                                     SA forums for this idea!
And then, in RJS
page.visual_effect :fade, 'toolbar', :duration => 1.5, :afterFinish => lambda do |step2|
  step2.call 'Toolbar.maintenance'
  step2.visual_effect :shake, 'score'
end




• The lambda only gets executed after the
    visual effect has finished
• Doesn’t matter if the computer takes longer
    than 1.5s
in Conclusion
Nobody’s Perfect!
Nobody’s Perfect!
• We love RJS despite its flaws
• It really does make your life easier, most of
  these issues would never be a problem in a
  low traffic app or admin interface
• The solutions we came up with are easy to
  implement
this presentation was
  brought to you by
this presentation was
  brought to you by


   Any questions?

More Related Content

Viewers also liked

CoffeeScript
CoffeeScriptCoffeeScript
CoffeeScriptEddie Kao
 
Flash Ecosystem and Open Source
Flash Ecosystem and Open SourceFlash Ecosystem and Open Source
Flash Ecosystem and Open SourceEddie Kao
 
Code Reading
Code ReadingCode Reading
Code ReadingEddie Kao
 
AS3 Better Practices
AS3 Better PracticesAS3 Better Practices
AS3 Better PracticesEddie Kao
 
Agenda 6è b setmana 02-gener-curs 16-17
Agenda 6è b setmana 02-gener-curs 16-17Agenda 6è b setmana 02-gener-curs 16-17
Agenda 6è b setmana 02-gener-curs 16-176sise
 

Viewers also liked (6)

CoffeeScript
CoffeeScriptCoffeeScript
CoffeeScript
 
Flash Ecosystem and Open Source
Flash Ecosystem and Open SourceFlash Ecosystem and Open Source
Flash Ecosystem and Open Source
 
Code Reading
Code ReadingCode Reading
Code Reading
 
AS3 Better Practices
AS3 Better PracticesAS3 Better Practices
AS3 Better Practices
 
測試
測試測試
測試
 
Agenda 6è b setmana 02-gener-curs 16-17
Agenda 6è b setmana 02-gener-curs 16-17Agenda 6è b setmana 02-gener-curs 16-17
Agenda 6è b setmana 02-gener-curs 16-17
 

Similar to Forumwarz and RJS: A Love/Hate Affair

Building a JavaScript Library
Building a JavaScript LibraryBuilding a JavaScript Library
Building a JavaScript Libraryjeresig
 
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript librariesJazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript librariesSimon Willison
 
Efficient JavaScript Development
Efficient JavaScript DevelopmentEfficient JavaScript Development
Efficient JavaScript Developmentwolframkriesing
 
Automated Frontend Testing
Automated Frontend TestingAutomated Frontend Testing
Automated Frontend TestingNeil Crosby
 
Progressive Enhancement with JavaScript and Ajax
Progressive Enhancement with JavaScript and AjaxProgressive Enhancement with JavaScript and Ajax
Progressive Enhancement with JavaScript and AjaxChristian Heilmann
 
Performance, Games, and Distributed Testing in JavaScript
Performance, Games, and Distributed Testing in JavaScriptPerformance, Games, and Distributed Testing in JavaScript
Performance, Games, and Distributed Testing in JavaScriptjeresig
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptGuy Royse
 
Usability in the GeoWeb
Usability in the GeoWebUsability in the GeoWeb
Usability in the GeoWebDave Bouwman
 
When To Use Ruby On Rails
When To Use Ruby On RailsWhen To Use Ruby On Rails
When To Use Ruby On Railsdosire
 
Intro To Django
Intro To DjangoIntro To Django
Intro To DjangoUdi Bauman
 
Presentations Unusual Java Bugs And Detecting Them Using Foss Tools
Presentations Unusual Java Bugs And Detecting Them Using Foss ToolsPresentations Unusual Java Bugs And Detecting Them Using Foss Tools
Presentations Unusual Java Bugs And Detecting Them Using Foss ToolsGanesh Samarthyam
 
Code Quality Practice and Tools
Code Quality Practice and ToolsCode Quality Practice and Tools
Code Quality Practice and ToolsBob Paulin
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceJesse Vincent
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersYehuda Katz
 
JavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureJavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureSimon Willison
 
Ajax Tutorial
Ajax TutorialAjax Tutorial
Ajax Tutorialoscon2007
 
How Not To Code Flex Applications
How Not To Code Flex ApplicationsHow Not To Code Flex Applications
How Not To Code Flex Applicationsjeff tapper
 
The 5 Layers of Web Accessibility
The 5 Layers of Web AccessibilityThe 5 Layers of Web Accessibility
The 5 Layers of Web AccessibilityDirk Ginader
 

Similar to Forumwarz and RJS: A Love/Hate Affair (20)

Building a JavaScript Library
Building a JavaScript LibraryBuilding a JavaScript Library
Building a JavaScript Library
 
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript librariesJazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
Jazz up your JavaScript: Unobtrusive scripting with JavaScript libraries
 
Efficient JavaScript Development
Efficient JavaScript DevelopmentEfficient JavaScript Development
Efficient JavaScript Development
 
Automated Frontend Testing
Automated Frontend TestingAutomated Frontend Testing
Automated Frontend Testing
 
Progressive Enhancement with JavaScript and Ajax
Progressive Enhancement with JavaScript and AjaxProgressive Enhancement with JavaScript and Ajax
Progressive Enhancement with JavaScript and Ajax
 
Performance, Games, and Distributed Testing in JavaScript
Performance, Games, and Distributed Testing in JavaScriptPerformance, Games, and Distributed Testing in JavaScript
Performance, Games, and Distributed Testing in JavaScript
 
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScriptjQuery & 10,000 Global Functions: Working with Legacy JavaScript
jQuery & 10,000 Global Functions: Working with Legacy JavaScript
 
Usability in the GeoWeb
Usability in the GeoWebUsability in the GeoWeb
Usability in the GeoWeb
 
When To Use Ruby On Rails
When To Use Ruby On RailsWhen To Use Ruby On Rails
When To Use Ruby On Rails
 
Ruby For Startups
Ruby For StartupsRuby For Startups
Ruby For Startups
 
Intro To Django
Intro To DjangoIntro To Django
Intro To Django
 
Presentations Unusual Java Bugs And Detecting Them Using Foss Tools
Presentations Unusual Java Bugs And Detecting Them Using Foss ToolsPresentations Unusual Java Bugs And Detecting Them Using Foss Tools
Presentations Unusual Java Bugs And Detecting Them Using Foss Tools
 
Code Quality Practice and Tools
Code Quality Practice and ToolsCode Quality Practice and Tools
Code Quality Practice and Tools
 
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret SauceBeijing Perl Workshop 2008 Hiveminder Secret Sauce
Beijing Perl Workshop 2008 Hiveminder Secret Sauce
 
SOLID Ruby, SOLID Rails
SOLID Ruby, SOLID RailsSOLID Ruby, SOLID Rails
SOLID Ruby, SOLID Rails
 
jQuery Presentation to Rails Developers
jQuery Presentation to Rails DevelopersjQuery Presentation to Rails Developers
jQuery Presentation to Rails Developers
 
JavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureJavaScript Libraries: The Big Picture
JavaScript Libraries: The Big Picture
 
Ajax Tutorial
Ajax TutorialAjax Tutorial
Ajax Tutorial
 
How Not To Code Flex Applications
How Not To Code Flex ApplicationsHow Not To Code Flex Applications
How Not To Code Flex Applications
 
The 5 Layers of Web Accessibility
The 5 Layers of Web AccessibilityThe 5 Layers of Web Accessibility
The 5 Layers of Web Accessibility
 

Recently uploaded

Annual General Meeting Presentation Slides
Annual General Meeting Presentation SlidesAnnual General Meeting Presentation Slides
Annual General Meeting Presentation SlidesKeppelCorporation
 
Innovation Conference 5th March 2024.pdf
Innovation Conference 5th March 2024.pdfInnovation Conference 5th March 2024.pdf
Innovation Conference 5th March 2024.pdfrichard876048
 
Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...
Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...
Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...lizamodels9
 
Case study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detailCase study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detailAriel592675
 
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCRashishs7044
 
Kenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith PereraKenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith Pereraictsugar
 
Intro to BCG's Carbon Emissions Benchmark_vF.pdf
Intro to BCG's Carbon Emissions Benchmark_vF.pdfIntro to BCG's Carbon Emissions Benchmark_vF.pdf
Intro to BCG's Carbon Emissions Benchmark_vF.pdfpollardmorgan
 
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCRashishs7044
 
Investment in The Coconut Industry by Nancy Cheruiyot
Investment in The Coconut Industry by Nancy CheruiyotInvestment in The Coconut Industry by Nancy Cheruiyot
Investment in The Coconut Industry by Nancy Cheruiyotictsugar
 
Islamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in IslamabadIslamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in IslamabadAyesha Khan
 
NewBase 19 April 2024 Energy News issue - 1717 by Khaled Al Awadi.pdf
NewBase  19 April  2024  Energy News issue - 1717 by Khaled Al Awadi.pdfNewBase  19 April  2024  Energy News issue - 1717 by Khaled Al Awadi.pdf
NewBase 19 April 2024 Energy News issue - 1717 by Khaled Al Awadi.pdfKhaled Al Awadi
 
BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,noida100girls
 
Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...
Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...
Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...lizamodels9
 
Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...
Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...
Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...lizamodels9
 
8447779800, Low rate Call girls in Saket Delhi NCR
8447779800, Low rate Call girls in Saket Delhi NCR8447779800, Low rate Call girls in Saket Delhi NCR
8447779800, Low rate Call girls in Saket Delhi NCRashishs7044
 
Organizational Structure Running A Successful Business
Organizational Structure Running A Successful BusinessOrganizational Structure Running A Successful Business
Organizational Structure Running A Successful BusinessSeta Wicaksana
 
BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,noida100girls
 
Contemporary Economic Issues Facing the Filipino Entrepreneur (1).pptx
Contemporary Economic Issues Facing the Filipino Entrepreneur (1).pptxContemporary Economic Issues Facing the Filipino Entrepreneur (1).pptx
Contemporary Economic Issues Facing the Filipino Entrepreneur (1).pptxMarkAnthonyAurellano
 
FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607dollysharma2066
 
Digital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdfDigital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdfJos Voskuil
 

Recently uploaded (20)

Annual General Meeting Presentation Slides
Annual General Meeting Presentation SlidesAnnual General Meeting Presentation Slides
Annual General Meeting Presentation Slides
 
Innovation Conference 5th March 2024.pdf
Innovation Conference 5th March 2024.pdfInnovation Conference 5th March 2024.pdf
Innovation Conference 5th March 2024.pdf
 
Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...
Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...
Call Girls In Connaught Place Delhi ❤️88604**77959_Russian 100% Genuine Escor...
 
Case study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detailCase study on tata clothing brand zudio in detail
Case study on tata clothing brand zudio in detail
 
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
8447779800, Low rate Call girls in New Ashok Nagar Delhi NCR
 
Kenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith PereraKenya Coconut Production Presentation by Dr. Lalith Perera
Kenya Coconut Production Presentation by Dr. Lalith Perera
 
Intro to BCG's Carbon Emissions Benchmark_vF.pdf
Intro to BCG's Carbon Emissions Benchmark_vF.pdfIntro to BCG's Carbon Emissions Benchmark_vF.pdf
Intro to BCG's Carbon Emissions Benchmark_vF.pdf
 
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
8447779800, Low rate Call girls in Uttam Nagar Delhi NCR
 
Investment in The Coconut Industry by Nancy Cheruiyot
Investment in The Coconut Industry by Nancy CheruiyotInvestment in The Coconut Industry by Nancy Cheruiyot
Investment in The Coconut Industry by Nancy Cheruiyot
 
Islamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in IslamabadIslamabad Escorts | Call 03070433345 | Escort Service in Islamabad
Islamabad Escorts | Call 03070433345 | Escort Service in Islamabad
 
NewBase 19 April 2024 Energy News issue - 1717 by Khaled Al Awadi.pdf
NewBase  19 April  2024  Energy News issue - 1717 by Khaled Al Awadi.pdfNewBase  19 April  2024  Energy News issue - 1717 by Khaled Al Awadi.pdf
NewBase 19 April 2024 Energy News issue - 1717 by Khaled Al Awadi.pdf
 
BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Greater Noida ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
 
Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...
Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...
Call Girls In Sikandarpur Gurgaon ❤️8860477959_Russian 100% Genuine Escorts I...
 
Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...
Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...
Lowrate Call Girls In Sector 18 Noida ❤️8860477959 Escorts 100% Genuine Servi...
 
8447779800, Low rate Call girls in Saket Delhi NCR
8447779800, Low rate Call girls in Saket Delhi NCR8447779800, Low rate Call girls in Saket Delhi NCR
8447779800, Low rate Call girls in Saket Delhi NCR
 
Organizational Structure Running A Successful Business
Organizational Structure Running A Successful BusinessOrganizational Structure Running A Successful Business
Organizational Structure Running A Successful Business
 
BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
BEST Call Girls In Old Faridabad ✨ 9773824855 ✨ Escorts Service In Delhi Ncr,
 
Contemporary Economic Issues Facing the Filipino Entrepreneur (1).pptx
Contemporary Economic Issues Facing the Filipino Entrepreneur (1).pptxContemporary Economic Issues Facing the Filipino Entrepreneur (1).pptx
Contemporary Economic Issues Facing the Filipino Entrepreneur (1).pptx
 
FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607FULL ENJOY Call girls in Paharganj Delhi | 8377087607
FULL ENJOY Call girls in Paharganj Delhi | 8377087607
 
Digital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdfDigital Transformation in the PLM domain - distrib.pdf
Digital Transformation in the PLM domain - distrib.pdf
 

Forumwarz and RJS: A Love/Hate Affair

  • 1. Forumwarz and RJS A love/hate affair
  • 2. An internet-based game about the internet
  • 4. The Internet is a wonderful, magical place!
  • 5. But it’s also terrible.
  • 7. John Gabriel’s Greater Internet Fuckwad Theory
  • 8.
  • 10. Have you heard of it? • One of the most popular forums in the world • Almost all its users are anonymous • Unfortunately, it’s hilarious.
  • 11. The anonymity of the Internet means you can be anything...
  • 12. You can be another ethnicity!
  • 13. You can be another species!
  • 14. You can even be beautiful!
  • 16. Are you going to explain what forumwarz is, or just show us hackneyed image macros all night?
  • 17. Role-Play an Internet User! Camwhore Emo Kid Troll
  • 18. Role-Play an Internet User! • Each player class features unique abilities and attacks • Many different ways to play • A detailed story line ties it all together
  • 19. An interface heavy in RJS (please endure this short demo)
  • 22. Some of our stats • ~30,000 user accounts since we launched one month ago • 2 million dynamic requests per day (25-55 req/s) • Static requests (images, stylesheets, js) are infrequent, since they’re set to expire in the far future • About 25GB of bandwidth per day
  • 23. Deployment • Single server: 3.0Ghz quad-core Xeon, 3GB of RAM • Nginx proxy to pack of 16 evented mongrels • Modest-sized memcached daemon
  • 24. Thank you AJAX! • One reason we can handle so many requests off a single server is because they’re tiny • We try to let the request get in and out as quickly as possible • RJS makes writing Javascript ridiculously simple
  • 25. why we rjs
  • 26. A simple example Example View #battle_log There's a large monster in front of you. = link_to_remote quot;Attack Monster!quot;, :action => 'attack' Example Controller def attack @monster = Monster.find(session[:current_monster_id]) @player = Player.find(session[:current_player_id]) @player.attack(@monster) update_page_tag do |page| page.insert_html :top, 'battle_log', :partial => 'attack_result' end end
  • 27. Pretty cool eh? • Without writing a line of javascript we’ve made a controller respond to an AJAX request • It’s fast. No need to request a full page for such a small update • It works great*
  • 28. * but it can haunt you
  • 29. Problem #1: Double Clicks • Often, people will click twice (or more!) in rapid succession • Your server gets two requests • If you’re lucky they will occur serially
  • 30. A Solution? • Use some javascript to prevent multiple clicks on the client side var ClickRegistry = { clicks : $H(), can_click_on : function(click_id) { return (this.clicks.get(click_id) == null) }, clicked_on : function(click_id) { this.clicks.set(click_id, true) }, done_call : function(click_id) { this.clicks.unset(click_id) } }
  • 31. A Solution? • Add a helper, link_once_remote def link_once_remote(name, options = {}, html_options = {}) click_id = html_options[:id] || Useful.unique_id options[:condition] = quot;ClickRegistry.can_click_on('#{click_id}')quot; prev_before = options[:before] options[:before] = quot;ClickRegistry.clicked_on('#{click_id}')quot; options[:before] << quot;; #{prev_before}quot; if prev_before prev_complete = options[:complete] options[:complete] = quot;ClickRegistry.done_call('#{click_id}')quot; options[:complete] << quot;; #{prev_complete}quot; if prev_complete link_to_remote(name, options, html_options) end
  • 32. Our Example: v.2 Example View #battle_log There's a large monster in front of you. = link_once_remote quot;Attack Monster!quot;, :action => 'attack'
  • 34. Why not? • Proxies or download “accelerators” • Browser add-ons might disagree with the javascript
  • 35. Also, it’s client validated! • Let’s face it: You can never, ever trust client validated data • Even if the Javascript worked perfectly, people would create greasemonkey scripts or bots to exploit it • Our users have already been doing this :(
  • 36. Server Side Validation • It’s the Rails way • If it fails, we can choose how to deal with the invalid request • Sometimes it makes sense to just ignore a request • Other times you might want to alert the user
  • 37. Problem #2:Validations • ActiveRecord validations can break during concurrency • In particular, the validates_uniqueness_of validation
  • 38. The Uniqueness Life-Cycle select * from battle_turns where turn = 1 and user_id = 1; if no rows returned insert into battle_turns (...) else return errors collection
  • 39. Transactions don’t help • With default isolation levels, reads aren’t locked • Assuming you have indexed the columns in your database you will get a DB error • So much for reporting errors to the user nicely!
  • 40. A solution? • Could monkey patch ActiveRecord to lock the tables • That’s fine if you don’t mind slowing your database to a crawl and a ridiculous amount of deadlocks
  • 41. A different solution? • You can rescue the DB error, and check to see if it’s a unique constraint that’s failing • This is what we did. It works, but it ties you to a particular database def save_with_catching_duplicates(*args) begin return save_without_catching_duplicates(*args) rescue ActiveRecord::StatementInvalid => error if error.to_s.include?(quot;Mysql::Error: Duplicate entryquot;) # Do what you want with the error. In our case we raise a # custom exception that we catch and deal with how we want end end end alias_method_chain :save, :catching_duplicates
  • 42. Problem #3: Animation • script.aculo.us has some awesome animation effects, and we use them often. • RJS gives you the great visual_effect helper method to do this: page.visual_effect :fade, 'toolbar' page.visual_effect :shake, 'score'
  • 43. When order matters • Often you’ll want to perform animation in order • RJS executes visual effects in parallel • There are two ways around this
  • 44. Effect Queues • You can queue together visual effects by assigning a name to a visual effect and a position in the queue. • Works great when all you are doing is animating • Does not work when you want to call custom Javascript at any point in the queue • Unfortunately we do this, in particular to deal with our toolbar
  • 45. page.delay page.visual_effect :fade, 'toolbar', :duration => 1.5 page.delay(1.5) do page.call 'Toolbar.maintenance' page.visual_effect :shake, 'score' end • Executes a block after a delay • If paired with :duration, you can have the block execute after a certain amount of time
  • 46. It’s me again! This also doesn’t work!
  • 47. Durations aren’t guaranteed • Your timing is at the whim of your client’s computer • Your effects can step on each other, preventing the animation from completing! • They will email you complaining that your app has “locked up”
  • 48. A solution? def visual_effect_with_callback_generation(name, id = false, options = {}) options.each do |key,value| if value.is_a?(Proc) js = update_page(&value) options[key] = quot;function() { #{js} }quot; end end visual_effect_without_callback_generation(name, id, options) end alias_method_chain :visual_effect, :callback_generation Thanks to skidooer on the SA forums for this idea!
  • 49. And then, in RJS page.visual_effect :fade, 'toolbar', :duration => 1.5, :afterFinish => lambda do |step2| step2.call 'Toolbar.maintenance' step2.visual_effect :shake, 'score' end • The lambda only gets executed after the visual effect has finished • Doesn’t matter if the computer takes longer than 1.5s
  • 52. Nobody’s Perfect! • We love RJS despite its flaws • It really does make your life easier, most of these issues would never be a problem in a low traffic app or admin interface • The solutions we came up with are easy to implement
  • 53. this presentation was brought to you by
  • 54. this presentation was brought to you by Any questions?