Advanced RESTful Rails

Post on 11-Sep-2014

30 views 3 download

Tags:

description

Ben Scofield's session on REST and Rails at Railsconf 2008

transcript

Advanced RESTful RailsBen Scofield

Constraints

Shall I compare thee to a summer's day?Thou art more lovely and more temperate.Rough winds do shake the darling buds of May,And summer's lease hath all too short a date.Sometime too hot the eye of heaven shines,And often is his gold complexion dimm'd;And every fair from fair some time declines,By chance, or nature's changing course, untrimm'd;But thy eternal summer shall not fade...

app controllers helpers models viewsconfig environments initializersdbdoclib taskslogpublic images javascripts stylesheetsscript performance processtest fixtures functional integration unit...

exists app/models/ exists app/controllers/ exists app/helpers/ create app/views/users exists test/functional/ exists test/unit/dependency model exists app/models/ exists test/unit/ exists test/fixtures/ create app/models/user.rb create test/unit/user_test.rb create test/fixtures/users.yml create db/migrate create db/migrate/20080531002035_create_users.rb create app/controllers/users_controller.rb create test/functional/users_controller_test.rb create app/helpers/users_helper.rb route map.resources :users

REST

Audience Participation!who is building restful applications?

212,000 Results

How do I handle ...

Difficulteven for the pros

class UsersController < ApplicationController # ...

def activate self.current_user = params[:activation_code].blank? ? false : # ... if logged_in? && !current_user.active? current_user.activate! flash[:notice] = "Signup complete!" end redirect_back_or_default('/') end

def suspend @user.suspend! redirect_to users_path end

def unsuspend @user.unsuspend! redirect_to users_path end

def destroy @user.delete! redirect_to users_path end

def purge @user.destroy redirect_to users_path endendRestful Authentication

What is REST?

Resources

hey-helen - flickr

Addressability

memestate - flickr

Representations

stevedave - flickr

Stateless*

http://www1.ncdc.noaa.gov/pub/data/images/usa-avhrr.gif

Audience Participation!why care?

Process

tiptoe - flickr

Domain

ejpphoto - flickr

Modeled

kerim - flickr

?

Identifyresources

Selectmethods to expose

Respectthe middleman

Simple

My Pull List

Releases

class ItemsController < ApplicationController # release listing page; filters on year/month/day from params def index; endend

ActionController::Routing::Routes.draw do |map| map.releases 'releases/:year/:month/:day', :controller => 'items', :action => 'index'end

Issues

class IssuesController < ApplicationController # issue detail page def show; endend

ActionController::Routing::Routes.draw do |map| map.resources :issuesend

Series

class TitlesController < ApplicationController # title detail page def show; endend

ActionController::Routing::Routes.draw do |map| map.resources :titlesend

class IssuesController < ApplicationController # issue listing page; could be series page def index; endend

ActionController::Routing::Routes.draw do |map| map.resources :titles, :has_many => [:issues]end

Users

class UsersController < ApplicationController before_filter :require_login, :only => [:edit, :update]

# edit account def edit; end

# update account def update; endend

ActionController::Routing::Routes.draw do |map| map.resources :usersend

Lists

class UsersController < ApplicationController # public view - pull list def show; endend

ActionController::Routing::Routes.draw do |map| map.resources :usersend

class TitlesController < ApplicationController # public view - pull list, given a user_id def index; endend

ActionController::Routing::Routes.draw do |map| map.resources :users, :has_many => [:titles]end

Advanced

Login*mc - flickr

class SessionsController < ApplicationController # login form def new; end

# login action def create; end

# logout action def destroy; endend

ActionController::Routing::Routes.draw do |map| map.resource :sessionend

Homepageseandreilinger - flickr

class HomepagesController < ApplicationController # homepage def show; endend

ActionController::Routing::Routes.draw do |map| map.resource :homepage map.root :homepageend

class ContentsController < ApplicationController # static content def show # code to find a template named according to params[:page] endend

ActionController::Routing::Routes.draw do |map| map.resources :contents map.root :controller => ‘contents’, :action => ‘show’, :page => ‘homepage’end

class AdsController < ApplicationController # ad index - the million dollar homepage def index; endend

ActionController::Routing::Routes.draw do |map| map.resources :ads map.root :adsend

Dashboardhel2005 - flickr

class DashboardsController < ApplicationController before_filter :require_login

# dashboard def show; endend

ActionController::Routing::Routes.draw do |map| map.resource :dashboardend

class InstrumentsController < ApplicationController before_filter :require_login

# dashboard def index @instruments = current_user.instruments endend

ActionController::Routing::Routes.draw do |map| map.resources :instrumentsend

Previewashoe - flickr

class PreviewsController < ApplicationController def create @post = Post.find(params[:post_id]) @post.attributes = params[:post]

render :template => 'posts/show' endend

ActionController::Routing::Routes.draw do |map| map.resources :posts, :has_one => [:preview]end

class PreviewsController < ApplicationController def create @post = Post.new(params[:post])

render :template => 'posts/show' endend

ActionController::Routing::Routes.draw do |map| map.resources :posts map.resource :previewend

Searchseandreilinger - flickr

class PostsController < ApplicationController def index if params[:query].blank? @posts = Post.find(:all) else @posts = Post.find_for_query(params[:query]) end endend

ActionController::Routing::Routes.draw do |map| map.resources :postsend

class SearchesController < ApplicationController def show @results = Searcher.find(params[:query]) endend

ActionController::Routing::Routes.draw do |map| map.resource :searchend

Wizardsdunechaser - flickr

/galleries/new

/restaurants/:id/photos/new

/restaurants/:id/photos/edit

ActionController::Routing::Routes.draw do |map| map.resources :galleries map.resources :galleries map.resources :restaurants, :has_many => [:photos]

map.with_options :controller => 'photos' do |p| p.edit_restaurant_photos 'restaurants/:restaurant_id/photos/edit', :action => 'edit' p.update_restaurant_photos 'restaurants/:restaurant_id/photos/update', :action => 'update', :conditions => {:method => :put} endend

Collectionswooandy - flickr

Web Servicesjosefstuefer - flickr

Text

Inventory

Staff Directory

HR

etc.

RESTful APISearch Application

Text

Inventory

Staff Directory

HR

etc.

RESTful API

RESTful API

RESTful API

RESTful API

Search Application

Administration

this slide left intentionally blank

ActionController::Routing::Routes.draw do |map| map.namespace :admin do |admin| admin.resources :invitations admin.resources :emails admin.resources :users admin.resources :features endend

Audience Participation!what gives you fits?

Rails, Specifically

<a href="/records/1" onclick="if (confirm('Are you sure?')) { 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;">Delete</a>

<%= link_to 'Delete', record, :method => 'delete', :confirm => 'Are you sure?' %>

Accessibility

ActionController::Routing::Routes.draw do |map| map.users 'users', :controller => ‘users’, :action => ‘index’ map.users 'users', :controller => ‘users’, :action => ‘create’ end

Hand-Written Routes

ActionController::Routing::Routes.draw do |map| map.resources :users # Install the default route as the lowest priority. map.connect ':controller/:action/:id' end

Default Routing

Collectionswooandy - flickr

class RecordsController < ApplicationController def index; end

def show; end

# ...end

Mixed

ActionController::Routing::Routes.draw do |map| map.resources :recordsend

Separated

ActionController::Routing::Routes.draw do |map| map.resource :record_list map.resources :recordsend

class RecordListsController < ApplicationController def show; end

# ...end

class RecordsController < ApplicationController def show; end

# ...end

Audience Participation!where’s rails bitten you?

Thanks!ben scofieldben.scofield@viget.comhttp://www.viget.com/extendhttp://www.culann.com