coined by Roy Fielding stands for REpresentational State Transfer
describes an architecture for web apps centered around resources
REST constraints
- client-server
- stateless
- cache
- uniform interface
- layered system
- code-on-demand
REST data elements
- resource
- resource identifier
- representation
- representation metadata
- resource metadata
- control data
Rails resource
- manipulated via HTTP methods
- URL addressable entity
- represented in different formats
operation SQL REST
create insert POST
read select GET
update update PUT
delete delete DELETE
Rails resource URLs
Traditional Rails RESTful Rails
POST /post/create POST /post
GET /post/show/1 GET /post/1
POST /post/update/1 PUT /post/1
POST /post/destroy/1 DELETE /post/1
Creating a resource
./script/generate scaffold_resource \
post \
title:string \
content:text \
created_at:datetime
creates
model, views, controller, helper
fixtures, unit tests, functional tests,
migration (fully functional!)
modifies
config/routes.rb
Model
app/models/post.rb
class Post < ActiveRecord::Base
end
nothing new!
View
app/views/posts/show.rhtml
Title:<%=h @post.title %>
Content:<%=h @post.content %>
Created at:<%=h @post.created_at %>
<%= link_to ‘Edit’, edit_post_path(@post) %> |
<%= link_to ‘Back’, posts_path %>
new syntax for link_to URLs!
Views: routes
config/routes.rb
ActionController::Routing::Routes.draw do |map|
map.resources :posts
end
defines path methods and URL methods
Action `````HTTP request````````` Path method
index GET /posts projects_path
show GET /posts/1 project_path(1)
new GET /posts/new new_project_path
edit GET /posts/1;edit edit_project_path(1)
create POST /posts projects_path
update PUT /posts/1 project_path(1)
delete DELETE /posts/1 project_path(1)
new
form_for(:post, :url => post_path) ...
edit
form_for(:post, :url => post_path(@post), \
:html => {:method => :put}) ...
destroy
link_to ‘Destroy’, post_path(post), :method => :delete
Controller
app/controllers/posts_controller.rb
def destroy
@post = Post.find(params[:id])
@post.destroy
respond_to do |format|
format.html { redirect_to posts_url }
format.xml { head :ok }
end
end
uses respond_to and post_url
Controller: routes
Traditional Rails
redirect_to :controller => ‘posts’, \
:action => ‘show’, :id => @post.id
RESTful Rails
redirect_to post_url(@post)
Each path method has equivalent URL method
Remember: use URL methods for redirect_to
Controller: respond_to
multiple representations of the resource
respond_to uses
accept HTTP-Header of the request
format appended to the request URL
register new formats in config/environment.rb
to extend responds_to
Mime::Type.register ‘image/png’, :png
Migration
db/migrate/001_create_posts.rb
class CreatePosts < ActiveRecord::Migration
def self.up
create_table :posts do |t|
t.column :title, :string
t.column :content, :text
t.column :created_at, :datetime
end
end
def self.down
drop_table :posts
end
end
Nested resources
strongly coupled resources
expressed in the URLs
creating a nested resource
./script/generate scaffold_resource comment \
post_id:integer created_at:datetime \
author:string content:text
models
models must be edited to express relationship
app/models/post.rb
class Post < ActiveRecord::Base
has_many :comments
end
app/models/comment.rb
class Comment < ActiveRecord::Base
belongs_to :post
end
routes
routes must be edited to reflect relationship
config/routes.rb
map.resources :comments
becomes
map.resources :posts do |posts|
posts.resources :comments
end
Path method Path
comments_path(1) /posts/1/comments
comment_path(1, 2) /posts/1/comments/2
new_comment_path(1) /posts/1/comments/new
edit_comment_path(1) /posts/1/comments/2;edit
controller
nested resources controllers must be adapted
def index
post = Post.find(params[:post_id])
@comments = post.comments.find(:all)
...
end
REST benefits
- clean URLS
- multiple representations
- less code
- CRUD oriented controllers
- clear application design
- scalability