Ajax Rails
-
Upload
hot -
Category
Technology
-
view
2.417 -
download
2
description
Transcript of Ajax Rails
Ajax on Rails
Stuart Halloway and Justin GehtlandCopyright 2005-6 Relevance, LLC
Ajax on Rails www.codecite.comSlide 1 of 54
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 [email protected] 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 "Software"), 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 "AS IS", 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 www.codecite.comSlide 2 of 54
Agenda
Prototype Support
Ajax requests
auto-update
UI observers
Scriptaculous Helpers
effects
widgets
JavaScript Generation
JavaScriptGenerator
rjs
JSONAjax on Rails www.codecite.comSlide 4 of 54
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 www.codecite.comSlide 5 of 54
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 www.codecite.comSlide 7 of 54
Creating a No-Op Form
<%= start_form_tag('javascript:void%200', {:method=> 'filter'}) %>
Ajax on Rails www.codecite.comSlide 8 of 54
Observing a Field By DOM ID
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Ajax on Rails www.codecite.comSlide 9 of 54
Frequency to Check for Field Changes
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Ajax on Rails www.codecite.comSlide 10 of 54
DOM ID to Update With Results
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Ajax on Rails www.codecite.comSlide 11 of 54
Show/Hide Progress Indicator
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Ajax on Rails www.codecite.comSlide 12 of 54
Query Parameters
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Ajax on Rails www.codecite.comSlide 13 of 54
Server URL
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Ajax on Rails www.codecite.comSlide 14 of 54
Why Full Path?
<%= observe_field :search, :frequency => 0.5, :update => 'ajaxWrapper', :complete=>"Element.hide('spinner')", :before=>"Element.show('spinner')", :with=>"'search=' + encodeURIComponent(value)", :url=>{:action=>'search', :only_path => false} %>
Pragforms Intended for Cross-Site Scripting
Most Ajax Apps Will Not Need This
Ajax on Rails www.codecite.comSlide 15 of 54
Rendered HTML + JavaScript
<input id="search" name="search" type="text" value="" /><script type="text/javascript">//<![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 www.codecite.comSlide 16 of 54
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 www.codecite.comSlide 17 of 54
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 www.codecite.comSlide 18 of 54
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 www.codecite.comSlide 19 of 54
XHR Helper Methods
Method Trigger
Ajax on Rails www.codecite.comSlide 20 of 54
link_to_remote user clicks a linkform_remote_tag user submits a formremote_form_for user submits a formobserve_field user changes a fieldobserve_form user changes any field in a formsubmit_to_remote user clicks button
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 www.codecite.comSlide 21 of 54
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 www.codecite.comSlide 23 of 54
What is Scriptaculous?
Effects and Widgets Library
Builds on Prototype
Driven and Inspired by Ruby on Rails
Simple and Elegant
Ajax on Rails www.codecite.comSlide 24 of 54
Autocomplete
Popup List of Choices
Load Possible Matches While User Edits
Several Helper Methods
Simplest Version Assumes AR-Style Model Object
Ajax on Rails www.codecite.comSlide 26 of 54
Text Input
<%= text_field 'user', 'favorite_language' %></p> <div class="auto_complete" id="user_favorite_language_auto_complete"></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %>
Ajax on Rails www.codecite.comSlide 27 of 54
DOM ID To AutoComplete
<%= text_field 'user', 'favorite_language' %></p> <div class="auto_complete" id="user_favorite_language_auto_complete"></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %>
Ajax on Rails www.codecite.comSlide 28 of 54
Placeholder DIV For Suggestions
<%= text_field 'user', 'favorite_language' %></p> <div class="auto_complete" id="user_favorite_language_auto_complete"></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %>
Ajax on Rails www.codecite.comSlide 29 of 54
Ajax Options (URL Required)
<%= text_field 'user', 'favorite_language' %></p> <div class="auto_complete" id="user_favorite_language_auto_complete"></div> <%= auto_complete_field :user_favorite_language, :url=>{:action=>'autocomplete_favorite_language'} %>
Ajax on Rails www.codecite.comSlide 30 of 54
Server Returns Simple HTML List
<ul class="autocomplete_list"> <% @languages.each do |l| %> <li class="autocomplete_item"><%= l %></li> <% end %></ul>
Ajax on Rails www.codecite.comSlide 31 of 54
Drag and Drop
Mark Elements as Draggable
Mark Elements as Drop Targets
Specify Callbacks
Ajax on Rails www.codecite.comSlide 32 of 54
Naming Convention: Model_Id
<ul id='pending_todo_list'> <% @pending_todos.each do |item| %> <% domid = "todo_#{item.id}" %> <li class="pending_todo" id='<%= domid %>'><%= item.name %></li> <%= draggable_element(domid, :ghosting=>true, :revert=>true) %> <% end %> </ul>
Ajax on Rails www.codecite.comSlide 33 of 54
Show Ghost Image While Dragging
<ul id='pending_todo_list'> <% @pending_todos.each do |item| %> <% domid = "todo_#{item.id}" %> <li class="pending_todo" id='<%= domid %>'><%= item.name %></li> <%= draggable_element(domid, :ghosting=>true, :revert=>true) %> <% end %> </ul>
Ajax on Rails www.codecite.comSlide 34 of 54
Snap Image Back After Drag
<ul id='pending_todo_list'> <% @pending_todos.each do |item| %> <% domid = "todo_#{item.id}" %> <li class="pending_todo" id='<%= domid %>'><%= item.name %></li> <%= draggable_element(domid, :ghosting=>true, :revert=>true) %> <% end %> </ul>
Ajax on Rails www.codecite.comSlide 35 of 54
DOM ID of Drop Target
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>"$('spinner').hide();", :before=>"$('spinner').show();", :hoverclass=>'hover', :with=>"'todo=' + encodeURIComponent(element.id.split('_').last())", :url=>{:action=>:todo_pending, :id=>@user})%>
Ajax on Rails www.codecite.comSlide 36 of 54
Only Accept Drops With Certain CSS Styles
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>"$('spinner').hide();", :before=>"$('spinner').show();", :hoverclass=>'hover', :with=>"'todo=' + encodeURIComponent(element.id.split('_').last())", :url=>{:action=>:todo_pending, :id=>@user})%>
Ajax on Rails www.codecite.comSlide 37 of 54
Various Ajax Options
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>"$('spinner').hide();", :before=>"$('spinner').show();", :hoverclass=>'hover', :with=>"'todo=' + encodeURIComponent(element.id.split('_').last())", :url=>{:action=>:todo_pending, :id=>@user})%>
Ajax on Rails www.codecite.comSlide 38 of 54
Set This CSS Class When a Valid Droppable Hovers
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>"$('spinner').hide();", :before=>"$('spinner').show();", :hoverclass=>'hover', :with=>"'todo=' + encodeURIComponent(element.id.split('_').last())", :url=>{:action=>:todo_pending, :id=>@user})%>
Ajax on Rails www.codecite.comSlide 39 of 54
Query Follows Naming Convention
<%= drop_receiving_element('pending_todos', :accept=>'completed_todo', :complete=>"$('spinner').hide();", :before=>"$('spinner').show();", :hoverclass=>'hover', :with=>"'todo=' + encodeURIComponent(element.id.split('_').last())", :url=>{:action=>:todo_pending, :id=>@user})%>
Ajax on Rails www.codecite.comSlide 40 of 54
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 www.codecite.comSlide 41 of 54
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 www.codecite.comSlide 42 of 54
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 www.codecite.comSlide 43 of 54
Some Basic Generator Calls
RJS Expression (Server) Generated JavaScript on Client
Ajax on Rails www.codecite.comSlide 44 of 54
page.alert('someMessage') alert("someMessage");page.redirect_to(:action=>'foo') window.location.href = "http://www.example.com/foo";page.call('myFunc', 'a_string', 42) myFunc("a_string", 42);page.assign('myVar', 42) myVar = 42;
Some Prototype Generator Calls
RJS Expression (Server) Generated JavaScript on Client
Ajax on Rails www.codecite.comSlide 45 of 54
page.show('someDomId') Element.show("someDomId");page.hide('someDomId') Element.hide("someDomId");page.toggle('someDomId') Element.toggle("someDomId");
Uses For JavaScriptGenerator
Update More Than One DOM Element
Update Element And Apply Behavior
Server Takes Control of The Page
Ajax on Rails www.codecite.comSlide 46 of 54
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 "pending_todo_list", :url=>{:action=>:sort_pending_todos, :id=>@user} end
Ajax on Rails www.codecite.comSlide 47 of 54
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 "pending_todo_list", :url=>{:action=>:sort_pending_todos, :id=>@user} end
Ajax on Rails www.codecite.comSlide 48 of 54
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 "pending_todo_list", :url=>{:action=>:sort_pending_todos, :id=>@user} end
Ajax on Rails www.codecite.comSlide 49 of 54
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 www.codecite.comSlide 50 of 54
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 www.codecite.comSlide 51 of 54
JSON Support
Rails Adds to_json to Objects
implemented in ActiveSupport::JSON
Used For Model-Centric Ajax
Ajax on Rails www.codecite.comSlide 52 of 54
JSON Example: Periodically Updating Chat
class ChatJsonController < ApplicationController def retrieve_chats headers['Content-Type'] = "text/json" @chats = get_chats render :text=>@chats.to_json endend
Ajax on Rails www.codecite.comSlide 53 of 54
References
ResourcesCodecite (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 CitedAjax 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 www.codecite.comSlide 54 of 54