SlideShare a Scribd company logo
Ajax on Rails
                Stuart Halloway and Justin Gehtland
                Copyright 2005-6 Relevance, LLC




Ajax on Rails                 Slide 1 of 54           www.codecite.com
License To Sample Code
This presentation is Copyright 2005-6, Relevance LLC. You may use any code you find here, subject to the terms below. If you want to deliver this
presentation, please send email to contact@relevancellc.com for permission and details.

Sample code associated with this presentation is Copyright (c) 2005-6 Relevance, LLC (www.relevancellc.com), unless otherwise marked. Code
citations from other projects are subject to the license(s) appropriate to those projects. You are responsible for complying with licenses for code you
use.

Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the quot;Softwarequot;), to
deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED quot;AS ISquot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT
LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.




Ajax on Rails                                                          Slide 2 of 54                                                    www.codecite.com
Rails's Role in Ajax




Ajax on Rails           Slide 3 of 54   www.codecite.com
Agenda

Prototype Support
     Ajax requests
     auto-update
     UI observers
Scriptaculous Helpers
     effects
     widgets
JavaScript Generation
     JavaScriptGenerator
     rjs
     JSON
Ajax on Rails               Slide 4 of 54   www.codecite.com
What is Prototype?

Core Support for Dynamic Web Apps
Hides Browser Oddities
Used by Scriptaculous and Rico
Driven and Inspired by Ruby on Rails
Simple and Elegant




Ajax on Rails                    Slide 5 of 54   www.codecite.com
Prototype's Role in Ajax




Ajax on Rails             Slide 6 of 54    www.codecite.com
Example: Ajax Search

Create a No-Op Form
Prototype Helper Observes User Action
Prototype Helper Submits Ajax Request
Server Renders a Partial
Update innerHTML of a Single Page Element




Ajax on Rails                   Slide 7 of 54   www.codecite.com
Creating a No-Op Form
<%= start_form_tag('javascript:void%200',
                   {:method=> 'filter'}) %>




Ajax on Rails                          Slide 8 of 54   www.codecite.com
Observing a Field By DOM ID
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>




Ajax on Rails                           Slide 9 of 54                   www.codecite.com
Frequency to Check for Field Changes
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>




Ajax on Rails                           Slide 10 of 54                  www.codecite.com
DOM ID to Update With Results
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>




Ajax on Rails                           Slide 11 of 54                  www.codecite.com
Show/Hide Progress Indicator
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>




Ajax on Rails                           Slide 12 of 54                  www.codecite.com
Query Parameters
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>




Ajax on Rails                           Slide 13 of 54                  www.codecite.com
Server URL
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>




Ajax on Rails                           Slide 14 of 54                  www.codecite.com
Why Full Path?
   <%= observe_field :search,
                    :frequency => 0.5,
                    :update => 'ajaxWrapper',
                    :complete=>quot;Element.hide('spinner')quot;,
                    :before=>quot;Element.show('spinner')quot;,
                    :with=>quot;'search=' + encodeURIComponent(value)quot;,
                    :url=>{:action=>'search', :only_path => false} %>

Pragforms Intended for Cross-Site Scripting
Most Ajax Apps Will Not Need This




Ajax on Rails                           Slide 15 of 54                  www.codecite.com
Rendered HTML + JavaScript
<input id=quot;searchquot; name=quot;searchquot; type=quot;textquot; value=quot;quot; />
<script type=quot;text/javascriptquot;>
//<![CDATA[
new Form.Element.Observer('search', 0.5, function(element, value) {
   Element.show('spinner');
   new Ajax.Updater('ajaxWrapper',
         'http://localhost:3010/user/search', {
      onComplete:function(request){
         Element.hide('spinner');
      },
      parameters:'search=' + encodeURIComponent(value)
   })
})
//]]>
</script>




Ajax on Rails                          Slide 16 of 54                 www.codecite.com
Server Side Renders a Partial
   def search
     if params[:search] && params[:search].size>0
       @user_pages, @users = paginate :users,
          :per_page => 10,
          :order => order_from_params,
          :conditions=>User.conditions_by_like(params[:search])
       logger.info @users.size
     else
       list
     end
     # params[:action] lets search and sort get _search and _sort
     render :partial=>params[:action], :layout=>false
   end




Ajax on Rails                           Slide 17 of 54              www.codecite.com
Server Side Implementation Does Not Use Layout
   def search
     if params[:search] && params[:search].size>0
       @user_pages, @users = paginate :users,
          :per_page => 10,
          :order => order_from_params,
          :conditions=>User.conditions_by_like(params[:search])
       logger.info @users.size
     else
       list
     end
     # params[:action] lets search and sort get _search and _sort
     render :partial=>params[:action], :layout=>false
   end




Ajax on Rails                           Slide 18 of 54              www.codecite.com
Generalizing From The Search Example

Rails Providers Helper Methods Like observe_field
Helpers Generate JavaScript Code
Options Passed Through to Prototype/Scriptaculous
     ruby hashes become JSON notation
Helpers Share Many Common Options




Ajax on Rails                      Slide 19 of 54      www.codecite.com
XHR Helper Methods
Method                   Trigger
link_to_remote           user clicks a link
form_remote_tag          user submits a form
remote_form_for          user submits a form
observe_field            user changes a field
observe_form             user changes any field in a form
submit_to_remote         user clicks button




Ajax on Rails              Slide 20 of 54                   www.codecite.com
Degradable Ajax

Ajax Apps That Also Function as Plain Old Web Pages
'Same URL' Strategy
     pass Ajax-specific header
     use partial for Ajax
     wrap partial in template/layout for POW
'Different URL' Strategy
     Ajax requests to one URL
     Non-Ajax requests to a different URL




Ajax on Rails                      Slide 21 of 54     www.codecite.com
Degrading on Same URL




Ajax on Rails           Slide 22 of 54   www.codecite.com
Degrading to Different URL
<%= link_to_remote('link',
                    {:update=>'jscheck'},
                    :href=>url_for(:action=>'no_javascript')) %>
<%= form_remote_tag(:update=>'jscheck',
                    :url=>{:action=>'yes_javascript'},
                    :html=>{:action=>'no_javascript', :method=>'post'}) %>




Ajax on Rails                          Slide 23 of 54                        www.codecite.com
What is Scriptaculous?

Effects and Widgets Library
Builds on Prototype
Driven and Inspired by Ruby on Rails
Simple and Elegant




Ajax on Rails                   Slide 24 of 54   www.codecite.com
Scriptaculous's Role in Ajax




Ajax on Rails               Slide 25 of 54     www.codecite.com
Autocomplete

Popup List of Choices
Load Possible Matches While User Edits
Several Helper Methods
Simplest Version Assumes AR-Style Model Object




Ajax on Rails                   Slide 26 of 54   www.codecite.com
Text Input
   <%= text_field 'user', 'favorite_language' %></p>
   <div class=quot;auto_completequot;
        id=quot;user_favorite_language_auto_completequot;></div>
   <%= auto_complete_field :user_favorite_language,
         :url=>{:action=>'autocomplete_favorite_language'} %>




Ajax on Rails                           Slide 27 of 54          www.codecite.com
DOM ID To AutoComplete
   <%= text_field 'user', 'favorite_language' %></p>
   <div class=quot;auto_completequot;
        id=quot;user_favorite_language_auto_completequot;></div>
   <%= auto_complete_field :user_favorite_language,
         :url=>{:action=>'autocomplete_favorite_language'} %>




Ajax on Rails                           Slide 28 of 54          www.codecite.com
Placeholder DIV For Suggestions
   <%= text_field 'user', 'favorite_language' %></p>
   <div class=quot;auto_completequot;
        id=quot;user_favorite_language_auto_completequot;></div>
   <%= auto_complete_field :user_favorite_language,
         :url=>{:action=>'autocomplete_favorite_language'} %>




Ajax on Rails                           Slide 29 of 54          www.codecite.com
Ajax Options (URL Required)
   <%= text_field 'user', 'favorite_language' %></p>
   <div class=quot;auto_completequot;
        id=quot;user_favorite_language_auto_completequot;></div>
   <%= auto_complete_field :user_favorite_language,
         :url=>{:action=>'autocomplete_favorite_language'} %>




Ajax on Rails                           Slide 30 of 54          www.codecite.com
Server Returns Simple HTML List
<ul class=quot;autocomplete_listquot;>
  <% @languages.each do |l| %>
  <li class=quot;autocomplete_itemquot;><%= l %></li>
  <% end %>
</ul>




Ajax on Rails                          Slide 31 of 54   www.codecite.com
Drag and Drop

Mark Elements as Draggable
Mark Elements as Drop Targets
Specify Callbacks




Ajax on Rails                   Slide 32 of 54   www.codecite.com
Naming Convention: Model_Id
<ul id='pending_todo_list'>
  <% @pending_todos.each do |item| %>
    <% domid = quot;todo_#{item.id}quot; %>
    <li class=quot;pending_todoquot; id='<%= domid %>'><%= item.name %></li>
    <%= draggable_element(domid, :ghosting=>true, :revert=>true) %>
  <% end %>
</ul>




Ajax on Rails                          Slide 33 of 54                  www.codecite.com
Show Ghost Image While Dragging
<ul id='pending_todo_list'>
  <% @pending_todos.each do |item| %>
    <% domid = quot;todo_#{item.id}quot; %>
    <li class=quot;pending_todoquot; id='<%= domid %>'><%= item.name %></li>
    <%= draggable_element(domid, :ghosting=>true, :revert=>true) %>
  <% end %>
</ul>




Ajax on Rails                          Slide 34 of 54                  www.codecite.com
Snap Image Back After Drag
<ul id='pending_todo_list'>
  <% @pending_todos.each do |item| %>
    <% domid = quot;todo_#{item.id}quot; %>
    <li class=quot;pending_todoquot; id='<%= domid %>'><%= item.name %></li>
    <%= draggable_element(domid, :ghosting=>true, :revert=>true) %>
  <% end %>
</ul>




Ajax on Rails                          Slide 35 of 54                  www.codecite.com
DOM ID of Drop Target
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo',
      :complete=>quot;$('spinner').hide();quot;,
      :before=>quot;$('spinner').show();quot;,
      :hoverclass=>'hover',
      :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;,
      :url=>{:action=>:todo_pending, :id=>@user})%>




Ajax on Rails                          Slide 36 of 54                        www.codecite.com
Only Accept Drops With Certain CSS Styles
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo',
      :complete=>quot;$('spinner').hide();quot;,
      :before=>quot;$('spinner').show();quot;,
      :hoverclass=>'hover',
      :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;,
      :url=>{:action=>:todo_pending, :id=>@user})%>




Ajax on Rails                          Slide 37 of 54                        www.codecite.com
Various Ajax Options
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo',
      :complete=>quot;$('spinner').hide();quot;,
      :before=>quot;$('spinner').show();quot;,
      :hoverclass=>'hover',
      :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;,
      :url=>{:action=>:todo_pending, :id=>@user})%>




Ajax on Rails                          Slide 38 of 54                        www.codecite.com
Set This CSS Class When a Valid Droppable Hovers
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo',
      :complete=>quot;$('spinner').hide();quot;,
      :before=>quot;$('spinner').show();quot;,
      :hoverclass=>'hover',
      :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;,
      :url=>{:action=>:todo_pending, :id=>@user})%>




Ajax on Rails                          Slide 39 of 54                        www.codecite.com
Query Follows Naming Convention
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo',
      :complete=>quot;$('spinner').hide();quot;,
      :before=>quot;$('spinner').show();quot;,
      :hoverclass=>'hover',
      :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;,
      :url=>{:action=>:todo_pending, :id=>@user})%>




Ajax on Rails                          Slide 40 of 54                        www.codecite.com
Distinct Style for Drop Areas
<style>
.hover {
  background-color: #888888;
}
#pending_todos ul li, #completed_todos ul li {
  list-style: none;
  cursor: -moz-grab;
}
#pending_todos, #completed_todos {
  border: 1px solid gray;
}




Ajax on Rails                          Slide 41 of 54   www.codecite.com
Distinct Style for Valid Drops on Hover
<style>
.hover {
  background-color: #888888;
}
#pending_todos ul li, #completed_todos ul li {
  list-style: none;
  cursor: -moz-grab;
}
#pending_todos, #completed_todos {
  border: 1px solid gray;
}




Ajax on Rails                          Slide 42 of 54     www.codecite.com
JavaScriptGenerator and RJS Templates

Added to Edge November 2005
Call Ruby Methods on Server-Side page Object
Generates JavaScript to Execute on Client
Methods for Prototype and Scriptaculous
Easy to Add Your Own




Ajax on Rails                    Slide 43 of 54         www.codecite.com
Some Basic Generator Calls
RJS Expression (Server)               Generated JavaScript on Client
page.alert('someMessage')             alert(quot;someMessagequot;);
page.redirect_to(:action=>'foo')      window.location.href = quot;http://www.example.com/fooquot;;
page.call('myFunc', 'a_string', 42)   myFunc(quot;a_stringquot;, 42);
page.assign('myVar', 42)              myVar = 42;




Ajax on Rails                              Slide 44 of 54                               www.codecite.com
Some Prototype Generator Calls
RJS Expression (Server)           Generated JavaScript on Client
page.show('someDomId')            Element.show(quot;someDomIdquot;);
page.hide('someDomId')            Element.hide(quot;someDomIdquot;);
page.toggle('someDomId')          Element.toggle(quot;someDomIdquot;);




Ajax on Rails                    Slide 45 of 54                    www.codecite.com
Uses For JavaScriptGenerator

Update More Than One DOM Element
Update Element And Apply Behavior
Server Takes Control of The Page




Ajax on Rails                      Slide 46 of 54   www.codecite.com
Rendering JavaScript From the Controller
       render :update do |page|
         page.replace_html 'pending_todos', :partial => 'pending_todos'
         page.replace_html 'completed_todos', :partial => 'completed_todos'
         page.sortable quot;pending_todo_listquot;,
             :url=>{:action=>:sort_pending_todos, :id=>@user}
       end




Ajax on Rails                             Slide 47 of 54                      www.codecite.com
Drag Move Updates More Than One Element
       render :update do |page|
         page.replace_html 'pending_todos', :partial => 'pending_todos'
         page.replace_html 'completed_todos', :partial => 'completed_todos'
         page.sortable quot;pending_todo_listquot;,
             :url=>{:action=>:sort_pending_todos, :id=>@user}
       end




Ajax on Rails                             Slide 48 of 54                      www.codecite.com
Drag Move Resets Sortable Behavior
       render :update do |page|
         page.replace_html 'pending_todos', :partial => 'pending_todos'
         page.replace_html 'completed_todos', :partial => 'completed_todos'
         page.sortable quot;pending_todo_listquot;,
             :url=>{:action=>:sort_pending_todos, :id=>@user}
       end




Ajax on Rails                             Slide 49 of 54                      www.codecite.com
Invoking UI Effects
   def update_many(options)
     render :update do |page|
       options.each do |k,v|
         page.replace_html k, :partial=>v
         page.visual_effect :highlight, k
       end
     end
   end




Ajax on Rails                           Slide 50 of 54   www.codecite.com
RJS Templates

View Files That End in .rjs
Same Object Model as render :update
Invoke Methods on page
Generated JavaScript Executes on Client




Ajax on Rails                     Slide 51 of 54   www.codecite.com
JSON Support

Rails Adds to_json to Objects
     implemented in ActiveSupport::JSON
Used For Model-Centric Ajax




Ajax on Rails                    Slide 52 of 54   www.codecite.com
JSON Example: Periodically Updating Chat
class ChatJsonController < ApplicationController
  def retrieve_chats
    headers['Content-Type'] = quot;text/jsonquot;
    @chats = get_chats
    render :text=>@chats.to_json
  end
end




Ajax on Rails                          Slide 53 of 54      www.codecite.com
References

Resources
Codecite (Presentations and Code Samples), http://www.codecite.com
Relevance Consulting and Development, http://www.relevancellc.com/main/services
Relevance Training, http://www.relevancellc.com/main/training
Relevance Weblog, http://blogs.relevancellc.com

Projects Cited
Ajax Labs, http://codecite.com/projects/ajax_labs.zip
Rails Exploration Application, http://codecite.com/projects/rails_xt.zip
Pragmatic Chat Sample Application, http://codecite.com/projects/pragmatic_chat.zip




Ajax on Rails                                       Slide 54 of 54                   www.codecite.com

More Related Content

Ajax Rails

  • 1. Ajax on Rails Stuart Halloway and Justin Gehtland Copyright 2005-6 Relevance, LLC Ajax on Rails Slide 1 of 54 www.codecite.com
  • 2. License To Sample Code This presentation is Copyright 2005-6, Relevance LLC. You may use any code you find here, subject to the terms below. If you want to deliver this presentation, please send email to contact@relevancellc.com for permission and details. Sample code associated with this presentation is Copyright (c) 2005-6 Relevance, LLC (www.relevancellc.com), unless otherwise marked. Code citations from other projects are subject to the license(s) appropriate to those projects. You are responsible for complying with licenses for code you use. Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the quot;Softwarequot;), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED quot;AS ISquot;, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. Ajax on Rails Slide 2 of 54 www.codecite.com
  • 3. Rails's Role in Ajax Ajax on Rails Slide 3 of 54 www.codecite.com
  • 4. Agenda Prototype Support Ajax requests auto-update UI observers Scriptaculous Helpers effects widgets JavaScript Generation JavaScriptGenerator rjs JSON Ajax on Rails Slide 4 of 54 www.codecite.com
  • 5. What is Prototype? Core Support for Dynamic Web Apps Hides Browser Oddities Used by Scriptaculous and Rico Driven and Inspired by Ruby on Rails Simple and Elegant Ajax on Rails Slide 5 of 54 www.codecite.com
  • 6. Prototype's Role in Ajax Ajax on Rails Slide 6 of 54 www.codecite.com
  • 7. Example: Ajax Search Create a No-Op Form Prototype Helper Observes User Action Prototype Helper Submits Ajax Request Server Renders a Partial Update innerHTML of a Single Page Element Ajax on Rails Slide 7 of 54 www.codecite.com
  • 8. Creating a No-Op Form <%= start_form_tag('javascript:void%200', {:method=> 'filter'}) %> Ajax on Rails Slide 8 of 54 www.codecite.com
  • 9. Observing a Field By DOM ID <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Ajax on Rails Slide 9 of 54 www.codecite.com
  • 10. Frequency to Check for Field Changes <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Ajax on Rails Slide 10 of 54 www.codecite.com
  • 11. DOM ID to Update With Results <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Ajax on Rails Slide 11 of 54 www.codecite.com
  • 12. Show/Hide Progress Indicator <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Ajax on Rails Slide 12 of 54 www.codecite.com
  • 13. Query Parameters <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Ajax on Rails Slide 13 of 54 www.codecite.com
  • 14. Server URL <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Ajax on Rails Slide 14 of 54 www.codecite.com
  • 15. Why Full Path? <%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>quot;Element.hide('spinner')quot;, :before=>quot;Element.show('spinner')quot;, :with=>quot;'search=' + encodeURIComponent(value)quot;, :url=>{:action=>'search', :only_path => false} %> Pragforms Intended for Cross-Site Scripting Most Ajax Apps Will Not Need This Ajax on Rails Slide 15 of 54 www.codecite.com
  • 16. Rendered HTML + JavaScript <input id=quot;searchquot; name=quot;searchquot; type=quot;textquot; value=quot;quot; /> <script type=quot;text/javascriptquot;> //<![CDATA[ new Form.Element.Observer('search', 0.5, function(element, value) { Element.show('spinner'); new Ajax.Updater('ajaxWrapper', 'http://localhost:3010/user/search', { onComplete:function(request){ Element.hide('spinner'); }, parameters:'search=' + encodeURIComponent(value) }) }) //]]> </script> Ajax on Rails Slide 16 of 54 www.codecite.com
  • 17. Server Side Renders a Partial def search if params[:search] && params[:search].size>0 @user_pages, @users = paginate :users, :per_page => 10, :order => order_from_params, :conditions=>User.conditions_by_like(params[:search]) logger.info @users.size else list end # params[:action] lets search and sort get _search and _sort render :partial=>params[:action], :layout=>false end Ajax on Rails Slide 17 of 54 www.codecite.com
  • 18. Server Side Implementation Does Not Use Layout def search if params[:search] && params[:search].size>0 @user_pages, @users = paginate :users, :per_page => 10, :order => order_from_params, :conditions=>User.conditions_by_like(params[:search]) logger.info @users.size else list end # params[:action] lets search and sort get _search and _sort render :partial=>params[:action], :layout=>false end Ajax on Rails Slide 18 of 54 www.codecite.com
  • 19. Generalizing From The Search Example Rails Providers Helper Methods Like observe_field Helpers Generate JavaScript Code Options Passed Through to Prototype/Scriptaculous ruby hashes become JSON notation Helpers Share Many Common Options Ajax on Rails Slide 19 of 54 www.codecite.com
  • 20. XHR Helper Methods Method Trigger link_to_remote user clicks a link form_remote_tag user submits a form remote_form_for user submits a form observe_field user changes a field observe_form user changes any field in a form submit_to_remote user clicks button Ajax on Rails Slide 20 of 54 www.codecite.com
  • 21. Degradable Ajax Ajax Apps That Also Function as Plain Old Web Pages 'Same URL' Strategy pass Ajax-specific header use partial for Ajax wrap partial in template/layout for POW 'Different URL' Strategy Ajax requests to one URL Non-Ajax requests to a different URL Ajax on Rails Slide 21 of 54 www.codecite.com
  • 22. Degrading on Same URL Ajax on Rails Slide 22 of 54 www.codecite.com
  • 23. Degrading to Different URL <%= link_to_remote('link', {:update=>'jscheck'}, :href=>url_for(:action=>'no_javascript')) %> <%= form_remote_tag(:update=>'jscheck', :url=>{:action=>'yes_javascript'}, :html=>{:action=>'no_javascript', :method=>'post'}) %> Ajax on Rails Slide 23 of 54 www.codecite.com
  • 24. What is Scriptaculous? Effects and Widgets Library Builds on Prototype Driven and Inspired by Ruby on Rails Simple and Elegant Ajax on Rails Slide 24 of 54 www.codecite.com
  • 25. Scriptaculous's Role in Ajax Ajax on Rails Slide 25 of 54 www.codecite.com
  • 26. Autocomplete Popup List of Choices Load Possible Matches While User Edits Several Helper Methods Simplest Version Assumes AR-Style Model Object Ajax on Rails Slide 26 of 54 www.codecite.com
  • 27. Text Input <%= text_field 'user', 'favorite_language' %></p> <div class=quot;auto_completequot; id=quot;user_favorite_language_auto_completequot;></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %> Ajax on Rails Slide 27 of 54 www.codecite.com
  • 28. DOM ID To AutoComplete <%= text_field 'user', 'favorite_language' %></p> <div class=quot;auto_completequot; id=quot;user_favorite_language_auto_completequot;></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %> Ajax on Rails Slide 28 of 54 www.codecite.com
  • 29. Placeholder DIV For Suggestions <%= text_field 'user', 'favorite_language' %></p> <div class=quot;auto_completequot; id=quot;user_favorite_language_auto_completequot;></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %> Ajax on Rails Slide 29 of 54 www.codecite.com
  • 30. Ajax Options (URL Required) <%= text_field 'user', 'favorite_language' %></p> <div class=quot;auto_completequot; id=quot;user_favorite_language_auto_completequot;></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %> Ajax on Rails Slide 30 of 54 www.codecite.com
  • 31. Server Returns Simple HTML List <ul class=quot;autocomplete_listquot;> <% @languages.each do |l| %> <li class=quot;autocomplete_itemquot;><%= l %></li> <% end %> </ul> Ajax on Rails Slide 31 of 54 www.codecite.com
  • 32. Drag and Drop Mark Elements as Draggable Mark Elements as Drop Targets Specify Callbacks Ajax on Rails Slide 32 of 54 www.codecite.com
  • 33. Naming Convention: Model_Id <ul id='pending_todo_list'> <% @pending_todos.each do |item| %> <% domid = quot;todo_#{item.id}quot; %> <li class=quot;pending_todoquot; id='<%= domid %>'><%= item.name %></li> <%= draggable_element(domid, :ghosting=>true, :revert=>true) %> <% end %> </ul> Ajax on Rails Slide 33 of 54 www.codecite.com
  • 34. Show Ghost Image While Dragging <ul id='pending_todo_list'> <% @pending_todos.each do |item| %> <% domid = quot;todo_#{item.id}quot; %> <li class=quot;pending_todoquot; id='<%= domid %>'><%= item.name %></li> <%= draggable_element(domid, :ghosting=>true, :revert=>true) %> <% end %> </ul> Ajax on Rails Slide 34 of 54 www.codecite.com
  • 35. Snap Image Back After Drag <ul id='pending_todo_list'> <% @pending_todos.each do |item| %> <% domid = quot;todo_#{item.id}quot; %> <li class=quot;pending_todoquot; id='<%= domid %>'><%= item.name %></li> <%= draggable_element(domid, :ghosting=>true, :revert=>true) %> <% end %> </ul> Ajax on Rails Slide 35 of 54 www.codecite.com
  • 36. DOM ID of Drop Target <%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>quot;$('spinner').hide();quot;, :before=>quot;$('spinner').show();quot;, :hoverclass=>'hover', :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;, :url=>{:action=>:todo_pending, :id=>@user})%> Ajax on Rails Slide 36 of 54 www.codecite.com
  • 37. Only Accept Drops With Certain CSS Styles <%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>quot;$('spinner').hide();quot;, :before=>quot;$('spinner').show();quot;, :hoverclass=>'hover', :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;, :url=>{:action=>:todo_pending, :id=>@user})%> Ajax on Rails Slide 37 of 54 www.codecite.com
  • 38. Various Ajax Options <%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>quot;$('spinner').hide();quot;, :before=>quot;$('spinner').show();quot;, :hoverclass=>'hover', :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;, :url=>{:action=>:todo_pending, :id=>@user})%> Ajax on Rails Slide 38 of 54 www.codecite.com
  • 39. Set This CSS Class When a Valid Droppable Hovers <%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>quot;$('spinner').hide();quot;, :before=>quot;$('spinner').show();quot;, :hoverclass=>'hover', :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;, :url=>{:action=>:todo_pending, :id=>@user})%> Ajax on Rails Slide 39 of 54 www.codecite.com
  • 40. Query Follows Naming Convention <%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>quot;$('spinner').hide();quot;, :before=>quot;$('spinner').show();quot;, :hoverclass=>'hover', :with=>quot;'todo=' + encodeURIComponent(element.id.split('_').last())quot;, :url=>{:action=>:todo_pending, :id=>@user})%> Ajax on Rails Slide 40 of 54 www.codecite.com
  • 41. Distinct Style for Drop Areas <style> .hover { background-color: #888888; } #pending_todos ul li, #completed_todos ul li { list-style: none; cursor: -moz-grab; } #pending_todos, #completed_todos { border: 1px solid gray; } Ajax on Rails Slide 41 of 54 www.codecite.com
  • 42. Distinct Style for Valid Drops on Hover <style> .hover { background-color: #888888; } #pending_todos ul li, #completed_todos ul li { list-style: none; cursor: -moz-grab; } #pending_todos, #completed_todos { border: 1px solid gray; } Ajax on Rails Slide 42 of 54 www.codecite.com
  • 43. JavaScriptGenerator and RJS Templates Added to Edge November 2005 Call Ruby Methods on Server-Side page Object Generates JavaScript to Execute on Client Methods for Prototype and Scriptaculous Easy to Add Your Own Ajax on Rails Slide 43 of 54 www.codecite.com
  • 44. Some Basic Generator Calls RJS Expression (Server) Generated JavaScript on Client page.alert('someMessage') alert(quot;someMessagequot;); page.redirect_to(:action=>'foo') window.location.href = quot;http://www.example.com/fooquot;; page.call('myFunc', 'a_string', 42) myFunc(quot;a_stringquot;, 42); page.assign('myVar', 42) myVar = 42; Ajax on Rails Slide 44 of 54 www.codecite.com
  • 45. Some Prototype Generator Calls RJS Expression (Server) Generated JavaScript on Client page.show('someDomId') Element.show(quot;someDomIdquot;); page.hide('someDomId') Element.hide(quot;someDomIdquot;); page.toggle('someDomId') Element.toggle(quot;someDomIdquot;); Ajax on Rails Slide 45 of 54 www.codecite.com
  • 46. Uses For JavaScriptGenerator Update More Than One DOM Element Update Element And Apply Behavior Server Takes Control of The Page Ajax on Rails Slide 46 of 54 www.codecite.com
  • 47. Rendering JavaScript From the Controller render :update do |page| page.replace_html 'pending_todos', :partial => 'pending_todos' page.replace_html 'completed_todos', :partial => 'completed_todos' page.sortable quot;pending_todo_listquot;, :url=>{:action=>:sort_pending_todos, :id=>@user} end Ajax on Rails Slide 47 of 54 www.codecite.com
  • 48. Drag Move Updates More Than One Element render :update do |page| page.replace_html 'pending_todos', :partial => 'pending_todos' page.replace_html 'completed_todos', :partial => 'completed_todos' page.sortable quot;pending_todo_listquot;, :url=>{:action=>:sort_pending_todos, :id=>@user} end Ajax on Rails Slide 48 of 54 www.codecite.com
  • 49. Drag Move Resets Sortable Behavior render :update do |page| page.replace_html 'pending_todos', :partial => 'pending_todos' page.replace_html 'completed_todos', :partial => 'completed_todos' page.sortable quot;pending_todo_listquot;, :url=>{:action=>:sort_pending_todos, :id=>@user} end Ajax on Rails Slide 49 of 54 www.codecite.com
  • 50. Invoking UI Effects def update_many(options) render :update do |page| options.each do |k,v| page.replace_html k, :partial=>v page.visual_effect :highlight, k end end end Ajax on Rails Slide 50 of 54 www.codecite.com
  • 51. RJS Templates View Files That End in .rjs Same Object Model as render :update Invoke Methods on page Generated JavaScript Executes on Client Ajax on Rails Slide 51 of 54 www.codecite.com
  • 52. JSON Support Rails Adds to_json to Objects implemented in ActiveSupport::JSON Used For Model-Centric Ajax Ajax on Rails Slide 52 of 54 www.codecite.com
  • 53. JSON Example: Periodically Updating Chat class ChatJsonController < ApplicationController def retrieve_chats headers['Content-Type'] = quot;text/jsonquot; @chats = get_chats render :text=>@chats.to_json end end Ajax on Rails Slide 53 of 54 www.codecite.com
  • 54. References Resources Codecite (Presentations and Code Samples), http://www.codecite.com Relevance Consulting and Development, http://www.relevancellc.com/main/services Relevance Training, http://www.relevancellc.com/main/training Relevance Weblog, http://blogs.relevancellc.com Projects Cited Ajax Labs, http://codecite.com/projects/ajax_labs.zip Rails Exploration Application, http://codecite.com/projects/rails_xt.zip Pragmatic Chat Sample Application, http://codecite.com/projects/pragmatic_chat.zip Ajax on Rails Slide 54 of 54 www.codecite.com