Tuesday, August 26, 2008

RESTful Rails in Short

What is REST?
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
Rails resource manipulations

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