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 (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

Usability in the GeoWeb
Usability in the GeoWebUsability in the GeoWeb
Usability in the GeoWeb
Dave Bouwman
 
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
Ganesh Samarthyam
 
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
Jesse Vincent
 
JavaScript Libraries: The Big Picture
JavaScript Libraries: The Big PictureJavaScript Libraries: The Big Picture
JavaScript Libraries: The Big Picture
Simon Willison
 
Ajax Tutorial
Ajax TutorialAjax Tutorial
Ajax Tutorial
oscon2007
 

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

FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
dollysharma2066
 
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
amitlee9823
 
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
amitlee9823
 
Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...
Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...
Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...
lizamodels9
 
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
dlhescort
 
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Dipal Arora
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
dlhescort
 

Recently uploaded (20)

FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
FULL ENJOY Call Girls In Majnu Ka Tilla, Delhi Contact Us 8377877756
 
B.COM Unit – 4 ( CORPORATE SOCIAL RESPONSIBILITY ( CSR ).pptx
B.COM Unit – 4 ( CORPORATE SOCIAL RESPONSIBILITY ( CSR ).pptxB.COM Unit – 4 ( CORPORATE SOCIAL RESPONSIBILITY ( CSR ).pptx
B.COM Unit – 4 ( CORPORATE SOCIAL RESPONSIBILITY ( CSR ).pptx
 
Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1Katrina Personal Brand Project and portfolio 1
Katrina Personal Brand Project and portfolio 1
 
Famous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st CenturyFamous Olympic Siblings from the 21st Century
Famous Olympic Siblings from the 21st Century
 
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
Call Girls Jp Nagar Just Call 👗 7737669865 👗 Top Class Call Girl Service Bang...
 
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
Call Girls Kengeri Satellite Town Just Call 👗 7737669865 👗 Top Class Call Gir...
 
A DAY IN THE LIFE OF A SALESMAN / WOMAN
A DAY IN THE LIFE OF A  SALESMAN / WOMANA DAY IN THE LIFE OF A  SALESMAN / WOMAN
A DAY IN THE LIFE OF A SALESMAN / WOMAN
 
Dr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdfDr. Admir Softic_ presentation_Green Club_ENG.pdf
Dr. Admir Softic_ presentation_Green Club_ENG.pdf
 
Uneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration PresentationUneak White's Personal Brand Exploration Presentation
Uneak White's Personal Brand Exploration Presentation
 
It will be International Nurses' Day on 12 May
It will be International Nurses' Day on 12 MayIt will be International Nurses' Day on 12 May
It will be International Nurses' Day on 12 May
 
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best ServicesMysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
Mysore Call Girls 8617370543 WhatsApp Number 24x7 Best Services
 
Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...
Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...
Russian Call Girls In Gurgaon ❤️8448577510 ⊹Best Escorts Service In 24/7 Delh...
 
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
Call Girls in Delhi, Escort Service Available 24x7 in Delhi 959961-/-3876
 
Cracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptxCracking the Cultural Competence Code.pptx
Cracking the Cultural Competence Code.pptx
 
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service AvailableCall Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
Call Girls Ludhiana Just Call 98765-12871 Top Class Call Girl Service Available
 
Monthly Social Media Update April 2024 pptx.pptx
Monthly Social Media Update April 2024 pptx.pptxMonthly Social Media Update April 2024 pptx.pptx
Monthly Social Media Update April 2024 pptx.pptx
 
Falcon's Invoice Discounting: Your Path to Prosperity
Falcon's Invoice Discounting: Your Path to ProsperityFalcon's Invoice Discounting: Your Path to Prosperity
Falcon's Invoice Discounting: Your Path to Prosperity
 
Ensure the security of your HCL environment by applying the Zero Trust princi...
Ensure the security of your HCL environment by applying the Zero Trust princi...Ensure the security of your HCL environment by applying the Zero Trust princi...
Ensure the security of your HCL environment by applying the Zero Trust princi...
 
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
Call Girls Navi Mumbai Just Call 9907093804 Top Class Call Girl Service Avail...
 
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service NoidaCall Girls In Noida 959961⊹3876 Independent Escort Service Noida
Call Girls In Noida 959961⊹3876 Independent Escort Service Noida
 

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?