SlideShare una empresa de Scribd logo
1 de 235
Descargar para leer sin conexión
Ruby on Rails
Part3: RESTful & Ajax
   ihower@gmail.com




     http://creativecommons.org/licenses/by-nc/2.5/tw/
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
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
Representational State Transfer
                   (     REST)


•   Roy Fielding       2000


•           SOAP XML-RPC

•     Web Service          API
    Amazon Yahoo! Google API
Rails RESTful
                ?
RESTful       :

designing controller
and action is chaos
controller
class EventsController < ApplicationController

index
show
new
create
edit
update
destroy
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.
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.
named routes
# routes.rb
map.connect '/:controller/:action/:id'

<%= link_to ‘text’, :controller => ‘events’,
                    :action => ‘show’,
                    :id => event.id %>
named routes
# routes.rb
map.connect '/:controller/:action/:id'

<%= link_to ‘text’, :controller => ‘events’,
                    :action => ‘show’,
                    :id => event.id %>

                    named route
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'
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) %>
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) %>
:



controllers   actions!!
The ideas from
   CRUD...
HTTP methods           (RFC 2616)




POST     GET     PUT         DELETE


Create   Read   Update        Delete
HTTP methods                  (RFC 2616)




POST     GET             PUT        DELETE


Create   Read          Update        Delete


          GET is defined as
           a safe method
/events/create

 /events/show/1

/events/update/1

/events/destroy/1
/events/create
                       Add
                    HTTP method
 /events/show/1

/events/update/1

/events/destroy/1
/events/create
                       Add
                    HTTP method
 /events/show/1

/events/update/1

/events/destroy/1
/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
/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.
CRUD-based action names
   get things simpler
create   show   update   delete


POST     GET     PUT     DELETE
CRUD-based action names
   get things simpler
create   show         update    delete


POST     GET           PUT     DELETE


         controller            CRUD
routes.rb
ActionController::Routing::Routes.draw do |map|
	 map.resources :events
end




                 named routes               actions
routes.rb
ActionController::Routing::Routes.draw do |map|
	 map.resources :events
end

                 a resource is
              something with URL



                 named routes               actions
routes.rb
ActionController::Routing::Routes.draw do |map|
	 map.resources :events
end

                    a resource is
                 something with URL



                    named routes            actions
             4
routes.rb
ActionController::Routing::Routes.draw do |map|
	 map.resources :events
end

                    a resource is
                 something with URL



                    named routes            actions
             4                                    7
routes.rb
ActionController::Routing::Routes.draw do |map|
	 map.resources :events
end

                    a resource is
                 something with URL



                    named routes            actions
             4                                    7
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
RESTful
CRUD
index                       The default
                                           request method is
                                                 GET


<%= link_to ‘event list’, events_path %>


class EventsController < ApplicationController

  def index
    @events = Event.find(:all)
  end
...
end
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
new/create
<%= link_to ‘new event’, new_event_path %>

class EventsController < ApplicationController
  def new
     @event = Event.new
  end
end
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 %>
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 %>
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 %>
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
edit/update
<%= link_to event.name, edit_event_path(event) %>

  class EventsController < ApplicationController
    def edit
      @event = Event.find(params[:id])
    end
  end
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 %>
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 %>
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
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
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
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
Singular and Plural RESTful
             Routes
• show, new, edit, destroy
• index, new, create
Singular and Plural RESTful
             Routes
• show, new, edit, destroy
• index, new, create
event_path(@event)
Singular and Plural RESTful
             Routes
• show, new, edit, destroy
• index, new, create
event_path(@event)
                 HTTP verb   show, update, destroy
Singular and Plural RESTful
             Routes
• show, new, edit, destroy
• index, new, create
event_path(@event)
                 HTTP verb   show, update, destroy

events_path
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
[custom route]_event[s]_path( event )
new, edit

     [custom route]_event[s]_path( event )
?
new, edit
                      ?

     [custom route]_event[s]_path( event )
_path
                      ?            _url              http://domain/
new, edit
                      ?

     [custom route]_event[s]_path( event )
_path
                            ?               _url           http://domain/
new, edit
                            ?

     [custom route]_event[s]_path( event )

            :method => GET | POST | PUT | DELETE
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id'
link_to event.name, :controller => ‘events’,
                    :action => :show , :id => event.id
map.connect ':controller/:action/:id'
link_to event.name, :controller => ‘events’,
                    :action => :show , :id => event.id
map.connect ':controller/:action/:id'
link_to event.name, :controller => ‘events’,
                    :action => :show , :id => event.id
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
PUT? DELETE?
The PUT&DELETE Cheat
The PUT&DELETE Cheat
•            PUT&DELETE method
The PUT&DELETE Cheat
•                   PUT&DELETE method
• Rails   _method
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>
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>
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>
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>
The Problem
The Problem
•   HTML            GET/POST   HTML forms
       PUT/DELETE
The Problem
•   HTML              GET/POST       HTML forms
       PUT/DELETE

•       XmlHttpRequest    ( Ajax request)
    GET/POST/PUT/DELETE/HEAD/OPTIONS
The Problem
•   HTML                GET/POST     HTML forms
       PUT/DELETE

•       XmlHttpRequest    ( Ajax request)
    GET/POST/PUT/DELETE/HEAD/OPTIONS

•   Firefox/Safari
The Problem
•   HTML                GET/POST     HTML forms
       PUT/DELETE

•       XmlHttpRequest    ( Ajax request)
    GET/POST/PUT/DELETE/HEAD/OPTIONS

•   Firefox/Safari

•   Opera              PUT/DELETE
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        !
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.)
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.
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 ?
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
RESTful
Scaffold
respond_to
       ?
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
format.html
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.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
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>
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
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
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
action

Don’t repeat yourself
formats
• format.html     • format.csv
• format.xml      • format.xls
• format.js       • format.yaml
• format.json     • format.txt
• format.atom     • more....
• format.rss
http://registrano.com/events/5381ae/attendees
http://registrano.com/events/5381ae/attendees
http://registrano.com/events/5381ae/attendees




http://registrano.com/events/5381ae/attendees.csv
http://registrano.com/events/5381ae/attendees




http://registrano.com/events/5381ae/attendees.csv

                http://registrano.com/events/5381ae/attendees.xls
(   UI   )
XML API
             JSON API




(   UI   )
XML API
                      JSON API




(   UI        )
         Adobe Flex
Rails: how to know?
URL
        http://localhost:3000/users.xml


     template
<%= link_to ‘User List’, formatted_users_path(:xml) %>



<a href=”/users.xml”>User List</a>
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
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
•        params[:format]

    GET /users/1?format=xml
•                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
custom format
# config/initializers/mime_types.rb
Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u
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
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
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
template
       ?
template

• format (minetype)      template generator
  (renderer)
• Rails2             action.minetype.renderer
           filename.html.erb
template
  def index
      @users = User.find(:all)
      respond_to do |format|
          format.html # index.html.erb
          format.xml # index.xml.builder
      end
  end
template
  def index
      @users = User.find(:all)
      respond_to do |format|
          format.html # index.html.erb
          format.xml # index.xml.builder
      end
  end
erb template
•     ruby code
•             HTML (   format.html)
    <h1><%= @event.name %></h1>
erb template
•     ruby code
•             HTML (   format.html)
    <h1><%= @event.name %></h1>
erb template
•     ruby code
•             HTML (   format.html)
    <h1><%= @event.name %></h1>




        <h1>OSDC 2008</h1>
erb template
•     ruby code
•             HTML (    format.html)
    <h1><%= @event.name %></h1>

                  show.html.erb


        <h1>OSDC 2008</h1>
builder template
 •        Ruby                XML
xml.instruct!
xml.title "This is a title"
xml.person do
  xml.first_name "Ryan"
  xml.last_name "Raaum"
end
builder template
 •        Ruby                XML
xml.instruct!
xml.title "This is a title"
xml.person do
  xml.first_name "Ryan"
  xml.last_name "Raaum"
end
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>
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>
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
Ajax on Rails
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
Ajax   (1)
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
RJS template
<%= link_to_remote ‘ajax show’, :url => event_path(@event) %>
RJS template
<%= link_to_remote ‘ajax show’, :url => event_path(@event) %>
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
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
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’
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’
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’
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 }
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 }
Ajax   (2)
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
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
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
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();
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;”>
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;”>
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;”>
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;”>
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;”>
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
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
RESTful
   7 actions
               ?
action
event has many attendees
Model design
class Event < ActiveRecord::Base
  has_many :attendees
end

class Attendee < ActiveRecord::Base
  belongs_to :event
end
nested resources(1)                                     controller
                                                       attendees

map.resources :events do |event|
    event.resources :attendees, :controller => 'event_attendees'
end
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) %>
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) %>
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) %>
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
nested resources(2)
<%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
nested resources(2)                        /events/2/attendees/3

<%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
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
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
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
Deep Nesting?
Resources should never be nested more than one level deep.
action
event memberships
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
RESTful design 1

map.resources :memberships
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
RESTful design 2
map.resources :groups do |group|
    group.resources :memberships
end
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
action
event has one map
singular resource route
•                resources

    map.resources :events



•                             resource
    map.resources :events do |event|
        event.resource :map, :controller => ‘event_maps’
    end
singular resource route
•                resources

    map.resources :events



•                             resource
    map.resources :events do |event|
        event.resource :map, :controller => ‘event_maps’
    end


                             RESTful   controller
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| %>
action
operate event state
  (open/closed)
map.resources :events do |event|
    event.resource :closure, :controller => 'event_closures'
end
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
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 %>
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 %>
why not
PUT closed=1 to /events/2
          Text
why not
PUT closed=1 to /events/2
          Text

 “a separate resource” or “an attribute of event”
action
search event
Extra Collection
               Routes
map.resources :events, :collection => { :search => :get }
Extra Collection
                Routes
map.resources :events, :collection => { :search => :get }

class EventsController < ApplicationController
  def search
    @events = Event.find_by_keyword(params[:keyword])
  end
end
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’ %>
action
a event dashboard
Extra Member Routes
map.resources :events, :member => { :dashboard => :get }
Extra Member Routes
 map.resources :events, :member => { :dashboard => :get }

class EventsController < ApplicationController
  def dashboard
    @event = Event.find(params[:id])
  end
end
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) %>
Route Customizations
  is not RESTful ??
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)
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.
action
sorting event
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
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’ %>
action
event admin
namespace
map.namespace :admin do |admin|
  admin.resources :events
end
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
Considerations(1)
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)
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.
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
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
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.
Considerations(3)
Considerations(3)

• one resources should be associated with
  one controller.
  (well, you can use one controller handle more than one resources)
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.
1 attendee Model
2 Resources related
     (2 Controller)
map.resources :attendees




  1 attendee Model
 2 Resources related
        (2 Controller)
map.resources :attendees




  1 attendee Model
 2 Resources related
        (2 Controller)
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)
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)
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)
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)
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
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
[namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
new, edit
                           ?
[namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
new, edit
                                         nested
                           ?
[namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
new, edit
                                         nested            ?    ?
                           ?
[namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
new, edit
                                         nested            ?    ?
                           ?
[namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)

            :method => GET | POST | PUT | DELETE
so, what’s REST style?
Nouns
Nouns
 URL
Nouns
 URL
Nouns
        URL



Verb
Nouns
                      URL



            Verb
finite HTTP methods
URL without      Nouns
      action          URL



             Verb
finite HTTP methods
URL without      Nouns
      action          URL



             Verb
finite HTTP methods
URL without      Nouns
      action          URL



             Verb            Content Types
finite HTTP methods
URL without      Nouns
      action          URL



             Verb            Content Types
finite HTTP methods               HTML, XML, JSON....etc
URL without      Nouns
                                    the resource have
      action          URL          many representations




             Verb            Content Types
finite HTTP methods               HTML, XML, JSON....etc
URL without      Nouns
                                    the resource have
      action          URL          many representations




             Verb            Content Types
finite HTTP methods               HTML, XML, JSON....etc
REST end.
Reference books:
• Rails Way(Addison Wesley)


• Advanced Rails    (Pragmatic)


• Code Review PDF        (peepcode.com)


• Rails2 PDF (peepcode.com)


• RESTful Web Services            (O’REILLY)

Más contenido relacionado

La actualidad más candente

AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkara JUG
 
Using and reusing CakePHP plugins
Using and reusing CakePHP pluginsUsing and reusing CakePHP plugins
Using and reusing CakePHP pluginsPierre MARTIN
 
TYPO3 Flow 2.0 (T3CON13 San Francisco)
TYPO3 Flow 2.0 (T3CON13 San Francisco)TYPO3 Flow 2.0 (T3CON13 San Francisco)
TYPO3 Flow 2.0 (T3CON13 San Francisco)Robert Lemke
 
Routing in Drupal 8
Routing in Drupal 8Routing in Drupal 8
Routing in Drupal 8kgoel1
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowVrann Tulika
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsBen Scofield
 
What's new in Rails 4
What's new in Rails 4What's new in Rails 4
What's new in Rails 4Fabio Akita
 
Routing in Drupal 8
Routing in Drupal 8Routing in Drupal 8
Routing in Drupal 8kgoel1
 
ActiveResource & REST
ActiveResource & RESTActiveResource & REST
ActiveResource & RESTRobbert
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsMark
 
ChocolateChip-UI
ChocolateChip-UIChocolateChip-UI
ChocolateChip-UIGeorgeIshak
 
Applications: A Series of States
Applications: A Series of StatesApplications: A Series of States
Applications: A Series of StatesTrek Glowacki
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Joao Lucas Santana
 
Codeigniter : Custom Routing - Manipulate Uri
Codeigniter : Custom Routing - Manipulate UriCodeigniter : Custom Routing - Manipulate Uri
Codeigniter : Custom Routing - Manipulate UriAbdul Malik Ikhsan
 
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編Masakuni Kato
 
Zazzy WordPress Navigation WordCamp Milwaukee
Zazzy WordPress Navigation WordCamp MilwaukeeZazzy WordPress Navigation WordCamp Milwaukee
Zazzy WordPress Navigation WordCamp MilwaukeeRachel Baker
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On RailsWen-Tien Chang
 

La actualidad más candente (20)

AnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFacesAnkaraJUG Kasım 2012 - PrimeFaces
AnkaraJUG Kasım 2012 - PrimeFaces
 
Using and reusing CakePHP plugins
Using and reusing CakePHP pluginsUsing and reusing CakePHP plugins
Using and reusing CakePHP plugins
 
TYPO3 Flow 2.0 (T3CON13 San Francisco)
TYPO3 Flow 2.0 (T3CON13 San Francisco)TYPO3 Flow 2.0 (T3CON13 San Francisco)
TYPO3 Flow 2.0 (T3CON13 San Francisco)
 
Routing in Drupal 8
Routing in Drupal 8Routing in Drupal 8
Routing in Drupal 8
 
Magento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request FlowMagento Live Australia 2016: Request Flow
Magento Live Australia 2016: Request Flow
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
What's new in Rails 4
What's new in Rails 4What's new in Rails 4
What's new in Rails 4
 
Routing in Drupal 8
Routing in Drupal 8Routing in Drupal 8
Routing in Drupal 8
 
ActiveResource & REST
ActiveResource & RESTActiveResource & REST
ActiveResource & REST
 
AngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.jsAngularJS vs. Ember.js vs. Backbone.js
AngularJS vs. Ember.js vs. Backbone.js
 
ChocolateChip-UI
ChocolateChip-UIChocolateChip-UI
ChocolateChip-UI
 
Pundit
PunditPundit
Pundit
 
Applications: A Series of States
Applications: A Series of StatesApplications: A Series of States
Applications: A Series of States
 
Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)Desenvolvimento web com Ruby on Rails (parte 2)
Desenvolvimento web com Ruby on Rails (parte 2)
 
Yerbabuena eRCP OSGi-based
Yerbabuena eRCP OSGi-basedYerbabuena eRCP OSGi-based
Yerbabuena eRCP OSGi-based
 
18.register login
18.register login18.register login
18.register login
 
Codeigniter : Custom Routing - Manipulate Uri
Codeigniter : Custom Routing - Manipulate UriCodeigniter : Custom Routing - Manipulate Uri
Codeigniter : Custom Routing - Manipulate Uri
 
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
浜松Rails3道場 其の壱 プロジェクト作成〜Rouging編
 
Zazzy WordPress Navigation WordCamp Milwaukee
Zazzy WordPress Navigation WordCamp MilwaukeeZazzy WordPress Navigation WordCamp Milwaukee
Zazzy WordPress Navigation WordCamp Milwaukee
 
Building Web Interface On Rails
Building Web Interface On RailsBuilding Web Interface On Rails
Building Web Interface On Rails
 

Destacado

CSCE "Rails Mass Assignment"
CSCE "Rails Mass Assignment"CSCE "Rails Mass Assignment"
CSCE "Rails Mass Assignment"Lukas Klein
 
Jeni intro1-bab11-pewarisan, polimorfisme, dan interface
Jeni intro1-bab11-pewarisan, polimorfisme, dan interfaceJeni intro1-bab11-pewarisan, polimorfisme, dan interface
Jeni intro1-bab11-pewarisan, polimorfisme, dan interfaceKristanto Wijaya
 
ALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateWen-Tien Chang
 
C19 Mutasi dan Polimorfisme
C19 Mutasi dan PolimorfismeC19 Mutasi dan Polimorfisme
C19 Mutasi dan PolimorfismeCatatan Medis
 
Pewarisan, Polimorfisme, dan Interface
Pewarisan, Polimorfisme, dan InterfacePewarisan, Polimorfisme, dan Interface
Pewarisan, Polimorfisme, dan InterfaceIbrahim Naki
 
Distributed Ruby and Rails
Distributed Ruby and RailsDistributed Ruby and Rails
Distributed Ruby and RailsWen-Tien Chang
 
Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)
Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)
Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)Melina Krisnawati
 
RSpec on Rails Tutorial
RSpec on Rails TutorialRSpec on Rails Tutorial
RSpec on Rails TutorialWen-Tien Chang
 
Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)
Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)
Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)Ibrahim Naki
 
Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀Wen-Tien Chang
 
淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2Wen-Tien Chang
 

Destacado (17)

Rails 生態圈一覽
Rails 生態圈一覽Rails 生態圈一覽
Rails 生態圈一覽
 
CSCE "Rails Mass Assignment"
CSCE "Rails Mass Assignment"CSCE "Rails Mass Assignment"
CSCE "Rails Mass Assignment"
 
Rails Security
Rails SecurityRails Security
Rails Security
 
Jeni intro1-bab11-pewarisan, polimorfisme, dan interface
Jeni intro1-bab11-pewarisan, polimorfisme, dan interfaceJeni intro1-bab11-pewarisan, polimorfisme, dan interface
Jeni intro1-bab11-pewarisan, polimorfisme, dan interface
 
ALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborateALPHAhackathon: How to collaborate
ALPHAhackathon: How to collaborate
 
C19 Mutasi dan Polimorfisme
C19 Mutasi dan PolimorfismeC19 Mutasi dan Polimorfisme
C19 Mutasi dan Polimorfisme
 
Pewarisan, Polimorfisme, dan Interface
Pewarisan, Polimorfisme, dan InterfacePewarisan, Polimorfisme, dan Interface
Pewarisan, Polimorfisme, dan Interface
 
Distributed Ruby and Rails
Distributed Ruby and RailsDistributed Ruby and Rails
Distributed Ruby and Rails
 
Kata pengantar
Kata pengantarKata pengantar
Kata pengantar
 
Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)
Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)
Java (Netbeans) Polymorphism - Object Oriented Programming (OOP)
 
RSpec & TDD Tutorial
RSpec & TDD TutorialRSpec & TDD Tutorial
RSpec & TDD Tutorial
 
RSpec on Rails Tutorial
RSpec on Rails TutorialRSpec on Rails Tutorial
RSpec on Rails Tutorial
 
Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)
Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)
Makalah Bahasa Indonesia (Ejaan Yang Disempurnakan)
 
Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀Git 版本控制系統 -- 從微觀到宏觀
Git 版本控制系統 -- 從微觀到宏觀
 
Polymorphism
PolymorphismPolymorphism
Polymorphism
 
Polymorphism
PolymorphismPolymorphism
Polymorphism
 
淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2淺談 Startup 公司的軟體開發流程 v2
淺談 Startup 公司的軟體開發流程 v2
 

Similar a Ruby on Rails : RESTful 和 Ajax

More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weiboshaokun
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful RailsViget Labs
 
Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)Joao Lucas Santana
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30fiyuer
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2RORLAB
 
Rupicon 2014 Action pack
Rupicon 2014 Action packRupicon 2014 Action pack
Rupicon 2014 Action packrupicon
 
Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
 Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg... Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...Brian Mann
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overviewYehuda Katz
 
Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à RubyMicrosoft
 
Simplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a VengeanceSimplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a Vengeancebrianauton
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the FinishYehuda Katz
 
Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2A.K.M. Ahsrafuzzaman
 
Boston Computing Review - Ruby on Rails
Boston Computing Review - Ruby on RailsBoston Computing Review - Ruby on Rails
Boston Computing Review - Ruby on RailsJohn Brunswick
 
Simple restfull app_s
Simple restfull app_sSimple restfull app_s
Simple restfull app_snetwix
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialYi-Ting Cheng
 

Similar a Ruby on Rails : RESTful 和 Ajax (20)

The Rails Way
The Rails WayThe Rails Way
The Rails Way
 
More to RoC weibo
More to RoC weiboMore to RoC weibo
More to RoC weibo
 
Advanced RESTful Rails
Advanced RESTful RailsAdvanced RESTful Rails
Advanced RESTful Rails
 
Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)Desenvolvimento web com Ruby on Rails (parte 4)
Desenvolvimento web com Ruby on Rails (parte 4)
 
How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30How to disassemble one monster app into an ecosystem of 30
How to disassemble one monster app into an ecosystem of 30
 
Action Controller Overview, Season 2
Action Controller Overview, Season 2Action Controller Overview, Season 2
Action Controller Overview, Season 2
 
Rupicon 2014 Action pack
Rupicon 2014 Action packRupicon 2014 Action pack
Rupicon 2014 Action pack
 
Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
 Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg... Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
Little Opinions, Big Possibilities: The Tools and Patterns for Building Larg...
 
Rails 3 overview
Rails 3 overviewRails 3 overview
Rails 3 overview
 
Introduction à Ruby
Introduction à RubyIntroduction à Ruby
Introduction à Ruby
 
Simplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a VengeanceSimplify Your Rails Controllers With a Vengeance
Simplify Your Rails Controllers With a Vengeance
 
Rails introduction
Rails introductionRails introduction
Rails introduction
 
Rails 3: Dashing to the Finish
Rails 3: Dashing to the FinishRails 3: Dashing to the Finish
Rails 3: Dashing to the Finish
 
Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2Ride on the Fast Track of Web with Ruby on Rails- Part 2
Ride on the Fast Track of Web with Ruby on Rails- Part 2
 
Boston Computing Review - Ruby on Rails
Boston Computing Review - Ruby on RailsBoston Computing Review - Ruby on Rails
Boston Computing Review - Ruby on Rails
 
Simple restfull app_s
Simple restfull app_sSimple restfull app_s
Simple restfull app_s
 
OSDC 2009 Rails Turtorial
OSDC 2009 Rails TurtorialOSDC 2009 Rails Turtorial
OSDC 2009 Rails Turtorial
 
Laravel 5
Laravel 5Laravel 5
Laravel 5
 
2007 Zend Con Mvc
2007 Zend Con Mvc2007 Zend Con Mvc
2007 Zend Con Mvc
 
Jsf
JsfJsf
Jsf
 

Más de Wen-Tien Chang

⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨Wen-Tien Chang
 
Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛Wen-Tien Chang
 
A brief introduction to Machine Learning
A brief introduction to Machine LearningA brief introduction to Machine Learning
A brief introduction to Machine LearningWen-Tien Chang
 
Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)Wen-Tien Chang
 
Exception Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyException Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyWen-Tien Chang
 
從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事Wen-Tien Chang
 
Yet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upYet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upWen-Tien Chang
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩Wen-Tien Chang
 
Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介Wen-Tien Chang
 
A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0Wen-Tien Chang
 
RubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingRubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingWen-Tien Chang
 
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean StartupWen-Tien Chang
 
那些 Functional Programming 教我的事
那些 Functional Programming 教我的事那些 Functional Programming 教我的事
那些 Functional Programming 教我的事Wen-Tien Chang
 
RubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & ClosingRubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & ClosingWen-Tien Chang
 
BDD style Unit Testing
BDD style Unit TestingBDD style Unit Testing
BDD style Unit TestingWen-Tien Chang
 
RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試Wen-Tien Chang
 
Service-Oriented Design and Implement with Rails3
Service-Oriented Design and Implement with Rails3Service-Oriented Design and Implement with Rails3
Service-Oriented Design and Implement with Rails3Wen-Tien Chang
 

Más de Wen-Tien Chang (20)

⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨⼤語⾔模型 LLM 應⽤開發入⾨
⼤語⾔模型 LLM 應⽤開發入⾨
 
Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛Ruby Rails 老司機帶飛
Ruby Rails 老司機帶飛
 
A brief introduction to Machine Learning
A brief introduction to Machine LearningA brief introduction to Machine Learning
A brief introduction to Machine Learning
 
Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)Exception Handling: Designing Robust Software in Ruby (with presentation note)
Exception Handling: Designing Robust Software in Ruby (with presentation note)
 
Exception Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in RubyException Handling: Designing Robust Software in Ruby
Exception Handling: Designing Robust Software in Ruby
 
從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事從 Classes 到 Objects: 那些 OOP 教我的事
從 Classes 到 Objects: 那些 OOP 教我的事
 
Yet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom upYet another introduction to Git - from the bottom up
Yet another introduction to Git - from the bottom up
 
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
A brief introduction to Vagrant – 原來 VirtualBox 可以這樣玩
 
Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介Ruby 程式語言綜覽簡介
Ruby 程式語言綜覽簡介
 
A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0A brief introduction to SPDY - 邁向 HTTP/2.0
A brief introduction to SPDY - 邁向 HTTP/2.0
 
RubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & ClosingRubyConf Taiwan 2012 Opening & Closing
RubyConf Taiwan 2012 Opening & Closing
 
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
從 Scrum 到 Kanban: 為什麼 Scrum 不適合 Lean Startup
 
Git Tutorial 教學
Git Tutorial 教學Git Tutorial 教學
Git Tutorial 教學
 
那些 Functional Programming 教我的事
那些 Functional Programming 教我的事那些 Functional Programming 教我的事
那些 Functional Programming 教我的事
 
RubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & ClosingRubyConf Taiwan 2011 Opening & Closing
RubyConf Taiwan 2011 Opening & Closing
 
BDD style Unit Testing
BDD style Unit TestingBDD style Unit Testing
BDD style Unit Testing
 
RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試RSpec 讓你愛上寫測試
RSpec 讓你愛上寫測試
 
Git and Github
Git and GithubGit and Github
Git and Github
 
Service-Oriented Design and Implement with Rails3
Service-Oriented Design and Implement with Rails3Service-Oriented Design and Implement with Rails3
Service-Oriented Design and Implement with Rails3
 
Rails3 changesets
Rails3 changesetsRails3 changesets
Rails3 changesets
 

Ruby on Rails : RESTful 和 Ajax

  • 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.
  • 6.
  • 7.
  • 9. RESTful : designing controller and action is chaos
  • 10. controller class EventsController < ApplicationController index show new create edit update destroy
  • 11. 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.
  • 12. 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.
  • 13. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, :action => ‘show’, :id => event.id %>
  • 14. named routes # routes.rb map.connect '/:controller/:action/:id' <%= link_to ‘text’, :controller => ‘events’, :action => ‘show’, :id => event.id %> named route
  • 15. 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'
  • 16. 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) %>
  • 17. 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) %>
  • 18. : controllers actions!!
  • 19. The ideas from CRUD...
  • 20. HTTP methods (RFC 2616) POST GET PUT DELETE Create Read Update Delete
  • 21. HTTP methods (RFC 2616) POST GET PUT DELETE Create Read Update Delete GET is defined as a safe method
  • 23. /events/create Add HTTP method /events/show/1 /events/update/1 /events/destroy/1
  • 24. /events/create Add HTTP method /events/show/1 /events/update/1 /events/destroy/1
  • 25. /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
  • 26. /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.
  • 27. CRUD-based action names get things simpler create show update delete POST GET PUT DELETE
  • 28. CRUD-based action names get things simpler create show update delete POST GET PUT DELETE controller CRUD
  • 29. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end named routes actions
  • 30. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions
  • 31. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4
  • 32. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4 7
  • 33. routes.rb ActionController::Routing::Routes.draw do |map| map.resources :events end a resource is something with URL named routes actions 4 7
  • 34. 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
  • 36. index The default request method is GET <%= link_to ‘event list’, events_path %> class EventsController < ApplicationController def index @events = Event.find(:all) end ... end
  • 37. 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
  • 38. new/create <%= link_to ‘new event’, new_event_path %> class EventsController < ApplicationController def new @event = Event.new end end
  • 39. 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 %>
  • 40. 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 %>
  • 41. 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 %>
  • 42. 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
  • 43. edit/update <%= link_to event.name, edit_event_path(event) %> class EventsController < ApplicationController def edit @event = Event.find(params[:id]) end end
  • 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" %> <% end %>
  • 45. 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 %>
  • 46. 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
  • 47. 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
  • 48. 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
  • 49. 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
  • 50. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create
  • 51. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event)
  • 52. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event) HTTP verb show, update, destroy
  • 53. Singular and Plural RESTful Routes • show, new, edit, destroy • index, new, create event_path(@event) HTTP verb show, update, destroy events_path
  • 54. 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
  • 56. new, edit [custom route]_event[s]_path( event )
  • 57. ? new, edit ? [custom route]_event[s]_path( event )
  • 58. _path ? _url http://domain/ new, edit ? [custom route]_event[s]_path( event )
  • 59. _path ? _url http://domain/ new, edit ? [custom route]_event[s]_path( event ) :method => GET | POST | PUT | DELETE
  • 62. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id
  • 63. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id
  • 64. map.connect ':controller/:action/:id' link_to event.name, :controller => ‘events’, :action => :show , :id => event.id
  • 65. 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
  • 68. The PUT&DELETE Cheat • PUT&DELETE method
  • 69. The PUT&DELETE Cheat • PUT&DELETE method • Rails _method
  • 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>
  • 71. 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>
  • 72. 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>
  • 73. 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>
  • 75. The Problem • HTML GET/POST HTML forms PUT/DELETE
  • 76. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS
  • 77. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS • Firefox/Safari
  • 78. The Problem • HTML GET/POST HTML forms PUT/DELETE • XmlHttpRequest ( Ajax request) GET/POST/PUT/DELETE/HEAD/OPTIONS • Firefox/Safari • Opera PUT/DELETE
  • 79. 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 !
  • 80. 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.)
  • 81. 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.
  • 82. 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 ?
  • 83. 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
  • 86. 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
  • 88. 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>
  • 89. 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
  • 90. 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>
  • 91. 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
  • 92. 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
  • 93. 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
  • 95. formats • format.html • format.csv • format.xml • format.xls • format.js • format.yaml • format.json • format.txt • format.atom • more.... • format.rss
  • 100. ( UI )
  • 101. XML API JSON API ( UI )
  • 102. XML API JSON API ( UI ) Adobe Flex
  • 103. Rails: how to know?
  • 104. URL http://localhost:3000/users.xml template <%= link_to ‘User List’, formatted_users_path(:xml) %> <a href=”/users.xml”>User List</a>
  • 105. 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
  • 106. 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
  • 107. params[:format] GET /users/1?format=xml
  • 108. 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
  • 109. custom format # config/initializers/mime_types.rb Mime::Type.register ‘audio/mpeg’, :mp3?Mime::Type.register ‘audio/mpegurl’, :m3u
  • 110. 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
  • 111. 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
  • 112. 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
  • 113. template ?
  • 114. template • format (minetype) template generator (renderer) • Rails2 action.minetype.renderer filename.html.erb
  • 115. template def index @users = User.find(:all) respond_to do |format| format.html # index.html.erb format.xml # index.xml.builder end end
  • 116. template def index @users = User.find(:all) respond_to do |format| format.html # index.html.erb format.xml # index.xml.builder end end
  • 117. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1>
  • 118. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1>
  • 119. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1> <h1>OSDC 2008</h1>
  • 120. erb template • ruby code • HTML ( format.html) <h1><%= @event.name %></h1> show.html.erb <h1>OSDC 2008</h1>
  • 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
  • 122. builder template • Ruby XML xml.instruct! xml.title "This is a title" xml.person do xml.first_name "Ryan" xml.last_name "Raaum" end
  • 123. 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>
  • 124. 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>
  • 125. 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
  • 127. 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
  • 128. Ajax (1)
  • 129. 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
  • 130. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %>
  • 131. RJS template <%= link_to_remote ‘ajax show’, :url => event_path(@event) %>
  • 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 end
  • 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
  • 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’
  • 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’
  • 136. 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’
  • 137. 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 }
  • 138. 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 }
  • 139. Ajax (2)
  • 140. 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
  • 141. 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
  • 142. 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
  • 143. 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();
  • 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 <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 <a href=”/users” onclick=”$.ajax(...blah...);return false;”>
  • 146. 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;”>
  • 147. 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;”>
  • 148. 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;”>
  • 149. 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
  • 150. 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
  • 151. RESTful 7 actions ?
  • 152. action event has many attendees
  • 153. Model design class Event < ActiveRecord::Base has_many :attendees end class Attendee < ActiveRecord::Base belongs_to :event end
  • 154. nested resources(1) controller attendees map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees' end
  • 155. 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) %>
  • 156. 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) %>
  • 157. 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) %>
  • 158. 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
  • 159. nested resources(2) <%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
  • 160. nested resources(2) /events/2/attendees/3 <%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
  • 161. 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
  • 162. 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
  • 163. 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
  • 164. Deep Nesting? Resources should never be nested more than one level deep.
  • 166. 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
  • 168. 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
  • 169. RESTful design 2 map.resources :groups do |group| group.resources :memberships end
  • 170. 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
  • 172. singular resource route • resources map.resources :events • resource map.resources :events do |event| event.resource :map, :controller => ‘event_maps’ end
  • 173. singular resource route • resources map.resources :events • resource map.resources :events do |event| event.resource :map, :controller => ‘event_maps’ end RESTful controller
  • 174. 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| %>
  • 175. action operate event state (open/closed)
  • 176. map.resources :events do |event| event.resource :closure, :controller => 'event_closures' end
  • 177. 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
  • 178. 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 %>
  • 179. 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 %>
  • 180. why not PUT closed=1 to /events/2 Text
  • 181. why not PUT closed=1 to /events/2 Text “a separate resource” or “an attribute of event”
  • 183. Extra Collection Routes map.resources :events, :collection => { :search => :get }
  • 184. Extra Collection Routes map.resources :events, :collection => { :search => :get } class EventsController < ApplicationController def search @events = Event.find_by_keyword(params[:keyword]) end end
  • 185. 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’ %>
  • 187. Extra Member Routes map.resources :events, :member => { :dashboard => :get }
  • 188. Extra Member Routes map.resources :events, :member => { :dashboard => :get } class EventsController < ApplicationController def dashboard @event = Event.find(params[:id]) end end
  • 189. 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) %>
  • 190. Route Customizations is not RESTful ??
  • 191. 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)
  • 192. 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.
  • 194. 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
  • 195. 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’ %>
  • 197. namespace map.namespace :admin do |admin| admin.resources :events end
  • 198. 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
  • 200. 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)
  • 201. 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.
  • 202. 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
  • 203. 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
  • 204. 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.
  • 206. Considerations(3) • one resources should be associated with one controller. (well, you can use one controller handle more than one resources)
  • 207. 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.
  • 208. 1 attendee Model 2 Resources related (2 Controller)
  • 209. map.resources :attendees 1 attendee Model 2 Resources related (2 Controller)
  • 210. map.resources :attendees 1 attendee Model 2 Resources related (2 Controller)
  • 211. 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)
  • 212. 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)
  • 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 1 attendee Model 2 Resources related (2 Controller)
  • 214. 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)
  • 215. 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
  • 216. 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
  • 218. new, edit ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
  • 219. new, edit nested ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
  • 220. new, edit nested ? ? ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
  • 221. new, edit nested ? ? ? [namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e) :method => GET | POST | PUT | DELETE
  • 222. so, what’s REST style?
  • 223. Nouns
  • 226. Nouns URL Verb
  • 227. Nouns URL Verb finite HTTP methods
  • 228. URL without Nouns action URL Verb finite HTTP methods
  • 229. URL without Nouns action URL Verb finite HTTP methods
  • 230. URL without Nouns action URL Verb Content Types finite HTTP methods
  • 231. URL without Nouns action URL Verb Content Types finite HTTP methods HTML, XML, JSON....etc
  • 232. URL without Nouns the resource have action URL many representations Verb Content Types finite HTTP methods HTML, XML, JSON....etc
  • 233. URL without Nouns the resource have action URL many representations Verb Content Types finite HTTP methods HTML, XML, JSON....etc
  • 235. Reference books: • Rails Way(Addison Wesley) • Advanced Rails (Pragmatic) • Code Review PDF (peepcode.com) • Rails2 PDF (peepcode.com) • RESTful Web Services (O’REILLY)