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