Ruby on Rails : RESTful&Ajax

Loading...

Flash Player 9 (or above) is needed to view presentations.
We have detected that you do not have it on your computer. To install it, go here.

0 comments

Post a comment

    Post a comment
    Embed Video
    Edit your comment Cancel

    4 Favorites

    Ruby on Rails : RESTful&Ajax - Presentation Transcript

    1. Ruby on Rails Part3: RESTful & Ajax ihower@gmail.com http://creativecommons.org/licenses/by-nc/2.5/tw/
    2. Browser MVC Model-View-Control HTTP request GET /users/1 route.rb UsersController Model def show @user = User.find(params[:id]) respond_to do |format| Database format.html format.xml end end #show.html.erb View <html> def index <h1>User Profile</h1> ...... <p><%= @user.nickname %></p> end </html> end
    3. Browser Controller Action MVC Model-View-Control HTTP request GET /users/1 route.rb UsersController Model def show @user = User.find(params[:id]) respond_to do |format| Database format.html format.xml end end #show.html.erb View <html> def index <h1>User Profile</h1> ...... <p><%= @user.nickname %></p> end </html> end
    4. Representational State Transfer ( REST) • Roy Fielding 2000 • SOAP XML-RPC • Web Service API Amazon Yahoo! Google API
    5. Rails RESTful ?
    6. RESTful : designing controller and action is chaos
    7. controller class EventsController < ApplicationController index show new create edit update destroy
    8. controller class EventsController < ApplicationController index watch_list show add_favorite new invite create join edit leave update white_member_list destroy black_member_list feeds deny_user add_comment allow_user show_comment edit_managers destroy_comment set_user_as_manager edit_comment set_user_as_member approve_comment ..... mark_comment_as_spam etc.
    9. controller class EventsController < ApplicationController index watch_list show add_favorite new create controller ??? invite join edit update actions leave ???? white_member_list destroy controller actions black_member_list ??? feeds deny_user add_comment allow_user show_comment edit_managers destroy_comment set_user_as_manager edit_comment set_user_as_member approve_comment ..... mark_comment_as_spam etc.
    10. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, :action => ‘show’, :id => event.id %>
    11. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, :action => ‘show’, :id => event.id %> named route
    12. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, :action => ‘show’, :id => event.id %> named route # routes.rb map.event '/events/:id', :controller => 'event', :action => 'show'
    13. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, :action => ‘show’, :id => event.id %> named route # routes.rb map.event '/events/:id', :controller => 'event', :action => 'show' <%= link_to ‘text’, event_path(event) %>
    14. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, hmm.... named routes :action => ‘show’, event_delete_path? :id => event.id %> event_create_path? named route events_path? # routes.rb events_new_path? map.event '/events/:id', :controller => 'event', :action => 'show' <%= link_to ‘text’, event_path(event) %>
    15. : controllers actions!!
    16. The ideas from CRUD...
    17. HTTP methods (RFC 2616) POST GET PUT DELETE Create Read Update Delete
    18. HTTP methods (RFC 2616) POST GET PUT DELETE Create Read Update Delete GET is defined as a safe method
    19. /events/create /events/show/1 /events/update/1 /events/destroy/1
    20. /events/create Add HTTP method /events/show/1 /events/update/1 /events/destroy/1
    21. /events/create Add HTTP method /events/show/1 /events/update/1 /events/destroy/1
    22. /events/create POST /events Add HTTP method /events/show/1 GET /events/1 /events/update/1 PUT /events/1 /events/destroy/1 DELETE /events/1
    23. /events/create POST /events Add HTTP method /events/show/1 GET /events/1 /events/update/1 PUT /events/1 /events/destroy/1 DELETE /events/1 Remove actions from URL, and we have simple named route.
    24. CRUD-based action names get things simpler create show update delete POST GET PUT DELETE
    25. CRUD-based action names get things simpler create show update delete POST GET PUT DELETE controller CRUD
    26. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end named routes actions
    27. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions
    28. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4
    29. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4 7
    30. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4 7
    31. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4 7 4 HTTP method
    32. RESTful CRUD
    33. index The default request method is GET <%= link_to ‘event list’, events_path %> class EventsController < ApplicationController def index @events = Event.find(:all) end ... end
    34. show The default request method is GET <%= link_to event.name, event_path(event) %> class EventsController < ApplicationController def show @event = Event.find(params[:id]) end ... end
    35. new/create <%= link_to ‘new event’, new_event_path %> class EventsController < ApplicationController def new @event = Event.new end end
    36. new/create <%= link_to ‘new event’, new_event_path %> class EventsController < ApplicationController def new @event = Event.new end end <% form_for @event, :url => events_path do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %>
    37. new/create <%= link_to ‘new event’, new_event_path %> class EventsController < ApplicationController def new @event = Event.new end end <% form_for @event, :url => events_path do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %>
    38. new/create <%= link_to ‘new event’, new_event_path %> class EventsController < ApplicationController def new In a form, the default @event = Event.new request method is end POST end <% form_for @event, :url => events_path do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %>
    39. new/create <%= link_to ‘new event’, new_event_path %> class EventsController < ApplicationController def new In a form, the default @event = Event.new request method is end POST end <% form_for @event, :url => events_path do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %> class EventsController < ApplicationController def create Event.create(params[:id]) end end
    40. edit/update <%= link_to event.name, edit_event_path(event) %> class EventsController < ApplicationController def edit @event = Event.find(params[:id]) end end
    41. edit/update <%= link_to event.name, edit_event_path(event) %> class EventsController < ApplicationController def edit @event = Event.find(params[:id]) end end <% form_for @event, :url => event_path(@event), :method => :put do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %>
    42. edit/update <%= link_to event.name, edit_event_path(event) %> class EventsController < ApplicationController def edit @event = Event.find(params[:id]) end end <% form_for @event, :url => event_path(@event), :method => :put do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> <% end %>
    43. edit/update <%= link_to event.name, edit_event_path(event) %> class EventsController < ApplicationController def edit @event = Event.find(params[:id]) end end <% form_for @event, :url => event_path(@event), :method => :put do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> the request <% end %> method is PUT
    44. edit/update <%= link_to event.name, edit_event_path(event) %> class EventsController < ApplicationController def edit @event = Event.find(params[:id]) end end <% form_for @event, :url => event_path(@event), :method => :put do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %> the request <% end %> method is PUT class EventsController < ApplicationController def create Event.create(params[:event]) end end
    45. the request destroy method is DELETE <%= link_to @event, event_path(@event), :method => :delete %> class EventsController < ApplicationController def destroy Event.find(params[:id]).destroy end ... end
    46. 4 HTTP methods, 4 URL helper, 7 actions Helper GET POST PUT DELETE /events/1 /events/1 /events/1 event_path(@event) show update destroy /events /events events_path index create /events/1/edit edit_event_path(@event) edit /events/new new_events_path new
    47. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create
    48. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event)
    49. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event) HTTP verb show, update, destroy
    50. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event) HTTP verb show, update, destroy events_path
    51. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event) HTTP verb show, update, destroy events_path HTTP verb index, create
    52. [custom route]_event[s]_path( event )
    53. new, edit [custom route]_event[s]_path( event )
    54. ? new, edit ? [custom route]_event[s]_path( event )
    55. _path ? _url http://domain/ new, edit ? [custom route]_event[s]_path( event )
    56. _path ? _url http://domain/ new, edit ? [custom route]_event[s]_path( event ) :method => GET | POST | PUT | DELETE
    57. map.connect ':controller/:action/:id'
    58. map.connect ':controller/:action/:id'
    59. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id
    60. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id
    61. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id
    62. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id link_to event.name, event_path(event) resources URL Helper
    63. PUT? DELETE?
    64. The PUT&DELETE Cheat
    65. The PUT&DELETE Cheat • PUT&DELETE method
    66. The PUT&DELETE Cheat • PUT&DELETE method • Rails _method
    67. The PUT&DELETE Cheat • PUT&DELETE method • Rails _method <form id="edit_events_1" method="post" action="/events/1"> <input type="hidden" value="put" name="_method"/> .... </form>
    68. The PUT&DELETE Cheat • PUT&DELETE method • Rails _method <form id="edit_events_1" method="post" action="/events/1"> <input type="hidden" value="put" name="_method"/> .... </form>
    69. The PUT&DELETE Cheat • PUT&DELETE method • Rails _method <form id="edit_events_1" method="post" action="/events/1"> <input type="hidden" value="put" name="_method"/> .... </form> <a onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute ('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit ();return false;" href="/events/1">Destroy</a>
    70. The PUT&DELETE Cheat • PUT&DELETE method • Rails _method <form id="edit_events_1" method="post" action="/events/1"> <input type="hidden" value="put" name="_method"/> .... </form> <a onclick="var f = document.createElement('form'); f.style.display = 'none'; this.parentNode.appendChild(f); f.method = 'POST'; f.action = this.href;var m = document.createElement('input'); m.setAttribute('type', 'hidden'); m.setAttribute ('name', '_method'); m.setAttribute('value', 'delete'); f.appendChild(m);f.submit ();return false;" href="/events/1">Destroy</a>
    71. The Problem
    72. The Problem • HTML GET/POST HTML forms PUT/DELETE
    73. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS
    74. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS • Firefox/Safari
    75. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS • Firefox/Safari • Opera PUT/DELETE
    76. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS • Firefox/Safari • Opera PUT/DELETE • IE DELETE !
    77. As a Ruby On Rails special, Prototype also reacts to other verbs (such as 'put' and 'delete' by actually using 'post' and putting an extra '_method' parameter with the originally requested method in there.)
    78. The type of request to make ("POST" or "GET"), default is "GET". Note: Other HTTP request methods, such as PUT Text and DELETE, can also be used here, but they are not supported by all browsers.
    79. 4 HTTP methods, 4 URL helper, 7 actions Helper GET POST PUT DELETE /events/1 /events/1 /events/1 event_path(@event) show update destroy /events /events events_path index create /events/1/edit edit_event_path(@event) edit /events/new new_events_path new It’s beauty, but RESTful can handle the real & complex world ?
    80. standardization on action name The heart of the Rails’s REST support is a technique for creating bundles of named routes automatically From Rails Way Chap.4
    81. RESTful Scaffold
    82. respond_to ?
    83. One Action, Multiple Response Formats def index @users = User.find(:all) respond_to do |format| format.html # index.html.erb format.xml { render :xml => @user.to_xml } end end
    84. format.html
    85. format.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <p> ihower at 2008-01-19 </p> </body> </html>
    86. format.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <p> ihower at 2008-01-19 </p> </body> </html> format.xml
    87. format.html <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd"> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <p> ihower at 2008-01-19 </p> </body> </html> format.xml <?xml version="1.0" encoding="UTF-8"?> <user> <created-at type="datetime">2008-01-19T09:55:32+08:00</created-at> <id type="integer">2</id> <name>ihower</name> <updated-at type="datetime">2008-01-19T09:55:32+08:00</updated-at> </user>
    88. you don't need this! def show_html @users = User.find(:all) end def show_xml @users = User.find(:all) render :xml => @user.to_xml end def show_json @user = User.find(:all) render :json => @user.to_json end
    89. you don't need this! def show_html @users = User.find(:all) end def show_xml @users = User.find(:all) render :xml => @user.to_xml end def show_json @user = User.find(:all) render :json => @user.to_json end
    90. you don't need this! def show_html @users = User.find(:all) end def show_xml @users = User.find(:all) render :xml => @user.to_xml end def show_json @user = User.find(:all) render :json => @user.to_json end
    91. action Don’t repeat yourself
    92. formats • format.html • format.csv • format.xml • format.xls • format.js • format.yaml • format.json • format.txt • format.atom • more.... • format.rss
    93. http://registrano.com/events/5381ae/attendees
    94. http://registrano.com/events/5381ae/attendees
    95. http://registrano.com/events/5381ae/attendees http://registrano.com/events/5381ae/attendees.csv
    96. http://registrano.com/events/5381ae/attendees http://registrano.com/events/5381ae/attendees.csv http://registrano.com/events/5381ae/attendees.xls
    97. ( UI )
    98. XML API JSON API ( UI )
    99. XML API JSON API ( UI ) Adobe Flex
    100. Rails: how to know?
    101. URL http://localhost:3000/users.xml template <%= link_to ‘User List’, formatted_users_path(:xml) %> <a href=”/users.xml”>User List</a>
    102. HTTP request Headers GET /users HTTP/1.1 Host: localhost:3000 User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; zh-TW; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 Accept: text/javascript, text/html, application/xml, text/xml, */* Accept-Language: zh-tw,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: Big5,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive X-Requested-With: XMLHttpRequest X-Prototype-Version: 1.6.0.1
    103. HTTP request Headers GET /users HTTP/1.1 Host: localhost:3000 User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; zh-TW; rv:1.8.1.13) Gecko/20080311 Firefox/2.0.0.13 Accept: text/javascript, text/html, application/xml, text/xml, */* Accept-Language: zh-tw,en-us;q=0.7,en;q=0.3 Accept-Encoding: gzip,deflate Accept-Charset: Big5,utf-8;q=0.7,*;q=0.7 Keep-Alive: 300 Connection: keep-alive Javascript Ajax X-Requested-With: XMLHttpRequest request X-Prototype-Version: 1.6.0.1
    104. • params[:format] GET /users/1?format=xml
    105. • Controller code class ApplicationController < ActionController::Base before_filter :adjust_format_for_iphone helper_method :iphone_user_agent? protected def adjust_format_for_iphone request.format = :iphone if iphone_user_agent? || iphone_subdomain? end # Request from an iPhone or iPod touch? # (Mobile Safari user agent) def iphone_user_agent? request.env["HTTP_USER_AGENT" ] && request.env["HTTP_USER_AGENT" ][/(Mobile/.+Safari)/] end def iphone_subdomain? return request.subdomains.first == "iphone" end end
    106. custom format # config/initializers/mime_types.rb Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u
    107. custom format # config/initializers/mime_types.rb Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u def show @mp3 = Mp3.find(params[:id]) respond_to do |format| format.html format.mp3 { redirect_to @mp3.url } format.m3u { render :text => @mp3.url } end end
    108. custom format # config/initializers/mime_types.rb Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u http://localhost:3000/mp3s/1.mp3 def show @mp3 = Mp3.find(params[:id]) respond_to do |format| format.html format.mp3 { redirect_to @mp3.url } format.m3u { render :text => @mp3.url } end end
    109. custom format # config/initializers/mime_types.rb Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u http://localhost:3000/mp3s/1.mp3 def show @mp3 = Mp3.find(params[:id]) respond_to do |format| format.html format.mp3 { redirect_to @mp3.url } format.m3u { render :text => @mp3.url } end end
    110. template ?
    111. template • format (minetype) template generator (renderer) • Rails2 action.minetype.renderer filename.html.erb
    112. template def index @users = User.find(:all) respond_to do |format| format.html # index.html.erb format.xml # index.xml.builder end end
    113. template def index @users = User.find(:all) respond_to do |format| format.html # index.html.erb format.xml # index.xml.builder end end
    114. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1>
    115. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1>
    116. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1> <h1>OSDC 2008</h1>
    117. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1> show.html.erb <h1>OSDC 2008</h1>
    118. builder template • Ruby XML xml.instruct! xml.title "This is a title" xml.person do xml.first_name "Ryan" xml.last_name "Raaum" end
    119. builder template • Ruby XML xml.instruct! xml.title "This is a title" xml.person do xml.first_name "Ryan" xml.last_name "Raaum" end
    120. builder template • Ruby XML xml.instruct! xml.title "This is a title" xml.person do xml.first_name "Ryan" xml.last_name "Raaum" end <?xml version="1.0" encoding="UTF-8"?> <title>This is a title</title> <person> <first_name>Ryan</first_name> <last_name>Raaum</last_name> </person>
    121. builder template • Ruby XML xml.instruct! xml.title "This is a title" xml.person do xml.first_name "Ryan" xml.last_name "Raaum" end show.xml.builder <?xml version="1.0" encoding="UTF-8"?> <title>This is a title</title> <person> <first_name>Ryan</first_name> <last_name>Raaum</last_name> </person>
    122. builder template (cont.) • Atom feed Rails2 Atom helper atom_feed do |feed| feed.title( @feed_title ) feed.updated((@events.first.created_at)) for event in @events feed.entry(event) do |entry| index.atom.builder entry.title(event.title) entry.content(event.description, :type => 'html') entry.author do |author| author.name( event.creator.nickname ) end end end end
    123. Ajax on Rails
    124. Ajax link_to_remote ‘Terms’, :url => terms_path, :update => ‘content’ <a onclick="$.ajax({async:true, beforeSend:function(xhr) {xhr.setRequestHeader ('Accept', 'text/html, */*')}, complete:function(request){ $("#content").html(request.responseText);}, dataType:'html', type:'get', url:'/terms'}); return false;" href="/terms"> </a> <div id=”content”> #content Browser </div> HTML <h1>ABC</j1> Ajax format.html <ul> <li>1</li> <li>2</li> </ul> Server
    125. Ajax (1)
    126. Ajax <a onclick="$.ajax({async:true, beforeSend:function(xhr) {xhr.setRequestHeader ('Accept', 'text/javascript, text/html, application/xml, text/xml, */*')}, dataType:'script', type:'get', url:'/user/1'}); return false;>User</a> <div id=”content”> </div> Javascript Browser $("#content").html(ʻ blahʼ); Ajax format.js $(“#sidebar”).html(ʻ blahʼ); $("#content").effect("highlight"); Server
    127. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %>
    128. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %>
    129. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) respond_to |format| format.js end end
    130. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) • respond_to |format| format.js end Ruby Javascript end
    131. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) • respond_to |format| format.js end Ruby Javascript end # show.js.rjs page.replace_html ‘content’, :partial =>’event’ page.visual_effect :highlight, ‘ content’
    132. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) • respond_to |format| format.js end Ruby Javascript end # show.js.rjs page.replace_html ‘content’, :partial =>’event’ page.visual_effect :highlight, ‘ content’
    133. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) • respond_to |format| format.js end Ruby Javascript end # show.js.rjs page.replace_html ‘content’, :partial =>’event’ page.visual_effect :highlight, ‘ content’
    134. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) • respond_to |format| format.js end Ruby Javascript end # show.js.rjs page.replace_html ‘content’, :partial =>’event’ page.visual_effect :highlight, ‘ content’ try { new Element.update("content", "blah"); new Effect.Highlight("content",{}); } catch (e) { alert('RJS error:nn' + e.toString()); alert('new Element.update ("content", "blah");nnew Effect.Highlight("content",{});'); throw e }
    135. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %> def show @event = Event.find(params[:id]) • respond_to |format| format.js end Ruby Javascript end # show.js.rjs page.replace_html ‘content’, :partial =>’event’ page.visual_effect :highlight, ‘ content’ Browser Server Javascript code try { new Element.update("content", "blah"); new Effect.Highlight("content",{}); } catch (e) { alert('RJS error:nn' + e.toString()); alert('new Element.update ("content", "blah");nnew Effect.Highlight("content",{});'); throw e }
    136. Ajax (2)
    137. inline RJS def show @note = Note.find(params[:id]) respond_to |format| format.js { render :update do |page| page.replace_html ‘content’, :partial =>’note’ page.visual_effect :highlight, ‘ content’ page << ‘alert(“hello world!”);’ end } end end
    138. inline RJS def show @note = Note.find(params[:id]) respond_to |format| format.js { render :update do |page| page.replace_html ‘content’, :partial =>’note’ page.visual_effect :highlight, ‘ content’ page << ‘alert(“hello world!”);’ end } end end
    139. inline RJS def show @note = Note.find(params[:id]) respond_to |format| format.js { render :update do |page| page.replace_html ‘content’, :partial =>’note’ page.visual_effect :highlight, ‘ content’ page << ‘alert(“hello world!”);’ end } end JavaScript end
    140. js.erb template <%=link_to_remote ‘ajax’, :url => posts_path %> def index ... • JavaScript • Rails 1.x respond_to |format| end format.js hack! end (google MinusMOR plugin) # index.js.erb $j("#foo").html(<%= (render :partial => 'note.html').to_json %>); $j("#foo").Highlight();
    141. respond_to : Graceful Degradation def index @users = User.find(:all) respond_to do |format| format.js { render :update do |page| page.replace_html ‘content’, ‘<p>blah</p>’ end } format.html #index.html.erb end end <a href=”/users” onclick=”$.ajax(...blah...);return false;”>
    142. respond_to : Graceful Degradation def index @users = User.find(:all) respond_to do |format| format.js { render :update do |page| page.replace_html ‘content’, ‘<p>blah</p>’ end } format.html #index.html.erb end end <a href=”/users” onclick=”$.ajax(...blah...);return false;”>
    143. respond_to : Graceful Degradation def index @users = User.find(:all) respond_to do |format| format.js { render :update do |page| page.replace_html ‘content’, ‘<p>blah</p>’ end } format.html #index.html.erb end end Browser Javascript <a href=”/users” onclick=”$.ajax(...blah...);return false;”>
    144. respond_to : Graceful Degradation def index @users = User.find(:all) respond_to do |format| format.js { render :update do |page| page.replace_html ‘content’, ‘<p>blah</p>’ end } format.html #index.html.erb end end Browser Javascript <a href=”/users” onclick=”$.ajax(...blah...);return false;”>
    145. respond_to : Graceful Degradation def index @users = User.find(:all) respond_to do |format| format.js { render :update do |page| page.replace_html ‘content’, ‘<p>blah</p>’ end } format.html #index.html.erb end end Browser Javascript Browser Javascript <a href=”/users” onclick=”$.ajax(...blah...);return false;”>
    146. Ajax $.ajax({ async:true, beforeSend:function(xhr) {xhr.setRequestHeader('Accept', 'text/xml, */*')}, type: “get”, url: “/users”, dataType: “xml”, success: function(xml){ // js blah code // js blah code Browser // js blah code }); XML data DOM <data title=”title”> Ajax format.xml <item>1</item> <item>2</item> <item>3</item> </data> Server
    147. Ajax $.ajax({ async:true, beforeSend:function(xhr) {xhr.setRequestHeader('Accept', 'text/json, */*')}, type: “get”, url: “/users”, dataType: “json”, success: function(json){ // js blah code // js blah code Browser // js blah code }); json data DOM [{"name": "aaaa", "updated_at": "2008/01/19 09:55:32 +0800", "id": 2, Ajax format.json "created_at": "2008/01/19 09:55:32 +0800"}, {"name": "bbbb222", "updated_at": "2008/01/19 09:56:11 +0800", "id": 3, "created_at": "2008/01/19 09:55:40 +0800"}] Server
    148. RESTful 7 actions ?
    149. action event has many attendees
    150. Model design class Event < ActiveRecord::Base has_many :attendees end class Attendee < ActiveRecord::Base belongs_to :event end
    151. nested resources(1) controller attendees map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees' end
    152. nested resources(1) controller attendees map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees' end <%= link_to ‘event attendees’, event_attendees_path(@event) %>
    153. nested resources(1) controller attendees map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees' end <%= link_to ‘event attendees’, event_attendees_path(@event) %>
    154. nested resources(1) controller attendees map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees' end /events/2/attendees <%= link_to ‘event attendees’, event_attendees_path(@event) %>
    155. nested resources(1) controller attendees map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees' end /events/2/attendees <%= link_to ‘event attendees’, event_attendees_path(@event) %> class EventAttendeesController < ApplicationController def index @attendees = Event.find(params[:event_id]).attendees end ... end
    156. nested resources(2) <%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
    157. nested resources(2) /events/2/attendees/3 <%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
    158. nested resources(2) /events/2/attendees/3 <%= link_to ‘show’, event_attendees_path(@event,@attendee) %> class EventAttendeesController < ApplicationController before_filter :find_event def show @attendees = @event.attendees.find(params[:id]) end protected def find_event @event = Event.find(params[:event_id]) end end
    159. nested resources(2) /events/2/attendees/3 <%= link_to ‘show’, event_attendees_path(@event,@attendee) %> class EventAttendeesController < ApplicationController before_filter :find_event def show @attendees = @event.attendees.find(params[:id]) end Q: ?? protected Attendee.find(params[:id]) def find_event @event = Event.find(params[:event_id]) end end
    160. nested resources(2) /events/2/attendees/3 <%= link_to ‘show’, event_attendees_path(@event,@attendee) %> class EventAttendeesController < ApplicationController before_filter :find_event def show @attendees = @event.attendees.find(params[:id]) end Q: ?? protected Attendee.find(params[:id]) def find_event @event = Event.find(params[:event_id]) Ans: end Scope Access end
    161. Deep Nesting? Resources should never be nested more than one level deep.
    162. action event memberships
    163. Model design class Event < ActiveRecord::Base has_many :memberships has_many :users, :through => :memberships end class User < ActiveRecord::Base has_many :memberships has_many :events, :through => :memberships end class Membership < ActiveRecord::Base belongs_to :event belongs_to :user end
    164. RESTful design 1 map.resources :memberships
    165. RESTful design 1 map.resources :memberships class MembershipsController < ApplicationController # POST /memberships?group_id=2&user_id=1 def create end # DELETE /memberships/3 def destroy end end
    166. RESTful design 2 map.resources :groups do |group| group.resources :memberships end
    167. RESTful design 2 map.resources :groups do |group| group.resources :memberships end class MembershipsController < ApplicationController # POST /group/2/memberships/?user_id=1 def create end # DELETE /group/2/memberships/3 def destroy end end
    168. action event has one map
    169. singular resource route • resources map.resources :events • resource map.resources :events do |event| event.resource :map, :controller => ‘event_maps’ end
    170. singular resource route • resources map.resources :events • resource map.resources :events do |event| event.resource :map, :controller => ‘event_maps’ end RESTful controller
    171. singular resource route (cont.) • URL helper • index action • show, edit update URL Helper id <%= link_to ‘Login’, event_map_path(@event) %> <% form_for :event_map, :url => event_map_path(@event) do |f| %>
    172. action operate event state (open/closed)
    173. map.resources :events do |event| event.resource :closure, :controller => 'event_closures' end
    174. map.resources :events do |event| event.resource :closure, :controller => 'event_closures' end class EventClosuresController < ApplicationController # POST /events/3/closure def create Event.find(params[:event_id]).close! end # DELETE /events/3/closure def destroy Event.find(params[:event_id]).open! end end
    175. map.resources :events do |event| event.resource :closure, :controller => 'event_closures' end class EventClosuresController < ApplicationController # POST /events/3/closure def create Event.find(params[:event_id]).close! end # DELETE /events/3/closure def destroy Event.find(params[:event_id]).open! end end <%= link_to ‘close’, event_closure_path(@event), :method => :post %>
    176. map.resources :events do |event| event.resource :closure, :controller => 'event_closures' end class EventClosuresController < ApplicationController # POST /events/3/closure def create Event.find(params[:event_id]).close! end # DELETE /events/3/closure def destroy Event.find(params[:event_id]).open! end end <%= link_to ‘close’, event_closure_path(@event), :method => :post %> <%= link_to ‘open’, event_closure_path(@event), :method => :delete %>
    177. why not PUT closed=1 to /events/2 Text
    178. why not PUT closed=1 to /events/2 Text “a separate resource” or “an attribute of event”
    179. action search event
    180. Extra Collection Routes map.resources :events, :collection => { :search => :get }
    181. Extra Collection Routes map.resources :events, :collection => { :search => :get } class EventsController < ApplicationController def search @events = Event.find_by_keyword(params[:keyword]) end end
    182. Extra Collection Routes map.resources :events, :collection => { :search => :get } class EventsController < ApplicationController def search @events = Event.find_by_keyword(params[:keyword]) end end <%= link_to ‘search’, search_events_path, :keyword => ‘osdc’ %>
    183. action a event dashboard
    184. Extra Member Routes map.resources :events, :member => { :dashboard => :get }
    185. Extra Member Routes map.resources :events, :member => { :dashboard => :get } class EventsController < ApplicationController def dashboard @event = Event.find(params[:id]) end end
    186. Extra Member Routes map.resources :events, :member => { :dashboard => :get } class EventsController < ApplicationController def dashboard @event = Event.find(params[:id]) end end <%= link_to ‘dashboard’, dashboard_event_path(event) %>
    187. Route Customizations is not RESTful ??
    188. Route Customizations is not RESTful ?? • you can think of it as a sub-resource of events resource. (and the sub-resource has only one action)
    189. Route Customizations is not RESTful ?? • you can think of it as a sub-resource of events resource. (and the sub-resource has only one action) • If you have too many extra routes, you should consider another resources.
    190. action sorting event
    191. Use query variables • Need not new resource def index sort_by = (params[:order] == ‘name’) ? ‘name’ : ‘created_at’ @events = Event.find(:all, :order => sort_by) end
    192. Use query variables • Need not new resource def index sort_by = (params[:order] == ‘name’) ? ‘name’ : ‘created_at’ @events = Event.find(:all, :order => sort_by) end <%= link_to ‘search’, events_path, :order => ‘name’ %>
    193. action event admin
    194. namespace map.namespace :admin do |admin| admin.resources :events end
    195. namespace map.namespace :admin do |admin| admin.resources :events end # /app/controllers/admin/events_controller.rb class Admin::EventsController < ApplicationController before_filter :require_admin def index .... end end
    196. Considerations(1)
    197. Considerations(1) • a REST resource does not map directly to model. It’s high-level abstractions of what’s available through your web app. (Not always 1-to-1, maybe 1-to-many or 1-to-zero)
    198. Considerations(1) • a REST resource does not map directly to model. It’s high-level abstractions of what’s available through your web app. (Not always 1-to-1, maybe 1-to-many or 1-to-zero) • You don’t need to use all 7 actions if you don’t need them.
    199. map.resource :session # This controller handles the login/logout function of the site. class SessionsController < ApplicationController def create self.current_user = User.authenticate(params[:login], params[:password]) if logged_in? redirect_back_or_default('/') else render :action => 'new' end end def destroy self.current_user.forget_me if logged_in? cookies.delete :auth_token reset_session redirect_back_or_default('/') end end
    200. map.resource :session # This controller handles the login/logout function of the site. class SessionsController < ApplicationController def create self.current_user = User.authenticate(params[:login], params[:password]) if logged_in? redirect_back_or_default('/') else render :action => 'new' end end def destroy self.current_user.forget_me if logged_in? cookies.delete :auth_token reset_session redirect_back_or_default('/') end end => session
    201. Considerations(2) • a RESTful controller may represent the creation or delete of only a concept. For example, a SpamsController create spam by changing a comment’s status to spam without adding any records to the DB.
    202. Considerations(3)
    203. Considerations(3) • one resources should be associated with one controller. (well, you can use one controller handle more than one resources)
    204. Considerations(3) • one resources should be associated with one controller. (well, you can use one controller handle more than one resources) • offload privileged views into either a different controller or action.
    205. 1 attendee Model 2 Resources related (2 Controller)
    206. map.resources :attendees 1 attendee Model 2 Resources related (2 Controller)
    207. map.resources :attendees 1 attendee Model 2 Resources related (2 Controller)
    208. map.resources :attendees class AttendeeController < ApplicationController before_filter :manager_required def show @person = @event.attendees.find(params[:id]) end end 1 attendee Model 2 Resources related (2 Controller)
    209. for event manager map.resources :attendees class AttendeeController < ApplicationController before_filter :manager_required def show @person = @event.attendees.find(params[:id]) end end 1 attendee Model 2 Resources related (2 Controller)
    210. for event manager map.resources :attendees class AttendeeController < ApplicationController before_filter :manager_required def show @person = @event.attendees.find(params[:id]) end end map.resources :registers 1 attendee Model 2 Resources related (2 Controller)
    211. for event manager map.resources :attendees class AttendeeController < ApplicationController before_filter :manager_required def show @person = @event.attendees.find(params[:id]) end end map.resources :registers 1 attendee Model 2 Resources related (2 Controller)
    212. for event manager map.resources :attendees class AttendeeController < ApplicationController before_filter :manager_required def show @person = @event.attendees.find(params[:id]) end end map.resources :registers class RegistersController < ApplicationController 1 attendee Model before_filter :login_required 2 Resources related def show @person = current_user.registers.find(params[:id]) (2 Controller) end end
    213. for event manager map.resources :attendees class AttendeeController < ApplicationController before_filter :manager_required def show @person = @event.attendees.find(params[:id]) end end map.resources :registers for attendeeing user class RegistersController < ApplicationController 1 attendee Model before_filter :login_required 2 Resources related def show @person = current_user.registers.find(params[:id]) (2 Controller) end end
    214. [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
    215. new, edit ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
    216. new, edit nested ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
    217. new, edit nested ? ? ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
    218. new, edit nested ? ? ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e) :method => GET | POST | PUT | DELETE
    219. so, what’s REST style?
    220. Nouns
    221. Nouns URL
    222. Nouns URL
    223. Nouns URL Verb
    224. Nouns URL Verb finite HTTP methods
    225. URL without Nouns action URL Verb finite HTTP methods
    226. URL without Nouns action URL Verb finite HTTP methods
    227. URL without Nouns action URL Verb Content Types finite HTTP methods
    228. URL without Nouns action URL Verb Content Types finite HTTP methods HTML, XML, JSON....etc
    229. URL without Nouns the resource have action URL many representations Verb Content Types finite HTTP methods HTML, XML, JSON....etc
    230. URL without Nouns the resource have action URL many representations Verb Content Types finite HTTP methods HTML, XML, JSON....etc
    231. REST end.
    232. Reference books: • Rails Way(Addison Wesley) • Advanced Rails (Pragmatic) • Code Review PDF (peepcode.com) • Rails2 PDF (peepcode.com) • RESTful Web Services (O’REILLY)

    + Wen-Tien ChangWen-Tien Chang, 2 months ago

    custom

    977 views, 4 favs, 2 embeds more stats

    More info about this document

    © All Rights Reserved

    Go to text version

    • Total Views 977
      • 889 on SlideShare
      • 88 from embeds
    • Comments 0
    • Favorites 4
    • Downloads 52
    Most viewed embeds
    • 87 views on http://ihower.idv.tw
    • 1 views on http://ihower.tw

    more

    All embeds
    • 87 views on http://ihower.idv.tw
    • 1 views on http://ihower.tw

    less

    Flagged as inappropriate Flag as inappropriate
    Flag as inappropriate

    Select your reason for flagging this presentation as inappropriate. If needed, use the feedback form to let us know more details.

    Cancel
    File a copyright complaint
    Having problems? Go to our helpdesk?

    Tags