RESTful Rails2
-
date post
12-Sep-2014 -
Category
Technology
-
view
13.233 -
download
5
description
Transcript of RESTful Rails2
![Page 2: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/2.jpg)
about me
• 張文鈿 (a.k.a ihower)http://ihower.idv.tw/blog/
• 和多鐵道員http://handlino.com
![Page 3: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/3.jpg)
![Page 4: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/4.jpg)
2007/12/7
![Page 5: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/5.jpg)
• RESTful Rails
• Bonus
• Testing
• Database & ActiveRecord
• Security
• Cache & Scale
• i18n and L10n
not include these:
agenda
![Page 6: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/6.jpg)
Rails Overview
• an open-source web framework for developing database-backed web applications
• Model-View-Control pattern
• a pure-Ruby development environment, from the Ajax in the view, to the request and response in the controller, to the domain model wrapping the database.
![Page 7: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/7.jpg)
MVCModel-View-Control
route.rbHTTP requestGET /users/1
Browser
UsersController
end
def show@user = User.find(params[:id])
respond_to do |format|format.htmlformat.xml
endend
def index......
end
Model
Database
#show.html.erb
<html> <h1>User Profile</h1> <p><%= @user.nickname %></p></html>
View
決定哪一個Controller 和 Action
![Page 8: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/8.jpg)
RESTful Rails進入主題
![Page 9: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/9.jpg)
RESTRepresentational State Transfer
表象化狀態轉變
![Page 10: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/10.jpg)
RESTRepresentational State Transfer
表象化狀態轉變
a lot of theory and abstract stuff
![Page 11: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/11.jpg)
![Page 12: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/12.jpg)
wait!we are not REST expert or devotee.
![Page 13: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/13.jpg)
wait!we are not REST expert or devotee.
到底 Rails RESTful 可以解決什麼問題? 到底 Rails RESTful 可以解決什麼問題?
![Page 14: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/14.jpg)
Before RESTful we have a big problem:
designing controller and action is chaos
![Page 15: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/15.jpg)
a simple controllerclass EventsController < ApplicationController
indexshownewcreateeditupdatedestroy
![Page 16: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/16.jpg)
a bloated controllerclass EventsController < ApplicationController
indexshownewcreateeditupdatedestroyfeedsadd_commentshow_commentdestroy_commentedit_commentapprove_commentmark_comment_as_spam
watch_listadd_favoriteinvitejoinleavewhite_member_listblack_member_listdeny_userallow_useredit_managersset_user_as_managerset_user_as_member.....etc.
![Page 17: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/17.jpg)
a bloated controllerclass EventsController < ApplicationController
indexshownewcreateeditupdatedestroyfeedsadd_commentshow_commentdestroy_commentedit_commentapprove_commentmark_comment_as_spam
watch_listadd_favoriteinvitejoinleavewhite_member_listblack_member_listdeny_userallow_useredit_managersset_user_as_managerset_user_as_member.....etc.
什麼時候該新寫 controller 呢???這些那些個 actions 又該怎麼放????
又該怎麼命名這些 controller 跟 actions 呢???
![Page 18: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/18.jpg)
named routes
<%= link_to ‘text’, :controller => ‘events’, :action => ‘show’,
:id => event.id %>
為求簡化,設定 named route# routes.rbmap.event '/events/:id', :controller => 'event', :action => 'show'
<%= link_to ‘text’, event_path(event) %>
# routes.rbmap.connect '/:controller/:action/:id'
event.to_param == event.id
![Page 19: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/19.jpg)
named routes
<%= link_to ‘text’, :controller => ‘events’, :action => ‘show’,
:id => event.id %>
為求簡化,設定 named route# routes.rbmap.event '/events/:id', :controller => 'event', :action => 'show'
<%= link_to ‘text’, event_path(event) %>
# routes.rbmap.connect '/:controller/:action/:id'
hmm.... 越來越多的 named routes event_delete_path?event_create_path?
events_path?events_new_path?
event.to_param == event.id
![Page 20: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/20.jpg)
decide how to name and organize the controllers and actions!!
we need a paradigm help us :
![Page 21: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/21.jpg)
The ideas fromCRUD...
![Page 22: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/22.jpg)
HTTP methods (RFC 2616)
POST GET PUT DELETE
Create Read Update Delete
GET is defined as a safe method
![Page 23: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/23.jpg)
/events/create
/events/show/1
/events/update/1
/events/destroy/1
POST /events
GET /events/1
PUT /events/1
DELETE /events/1
Add HTTP method
Remove actions from URL, andwe have simple named route.
![Page 24: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/24.jpg)
create show update delete
POST GET PUT DELETE
CRUD-based action namesget things simpler
盡量讓每個 controller 只負責一組 CRUD
![Page 25: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/25.jpg)
routes.rb
自動建立一組 named routes 對應到 actions
ActionController::Routing::Routes.draw do |map| map.resources :eventsend
a resource is something with URL
744 HTTP method
![Page 26: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/26.jpg)
index
class EventsController < ApplicationController
def index @events = Event.find(:all) end...end
<%= link_to ‘event list’, events_path %>
The default request method is
GET
![Page 27: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/27.jpg)
show
class EventsController < ApplicationController
def show @event = Event.find(params[:id]) end...end
<%= link_to event.name, event_path(event) %>
The default request method is
GET
![Page 28: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/28.jpg)
new/create
class EventsController < ApplicationController def create
Event.create(params[:id]) endend
<% form_for @event, :url => events_path do |f| %> <%= f.text_field :name %> <%= f.submit "Create" %><% end %>
<%= link_to ‘new event’, new_event_path %>
In a form, the default request method is
POST
class EventsController < ApplicationController def new
@event = Event.new endend
![Page 29: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/29.jpg)
edit/update
class EventsController < ApplicationController def create
Event.create(params[:id]) endend
<% form_for @event, :url => event_path(@event), :method => :put do |f| %>
<%= f.text_field :name %> <%= f.submit "Create" %><% end %>
<%= link_to event.name, edit_event_path(event) %>
class EventsController < ApplicationController def edit
@event = Event.find(params[:id]) endend
the request method is
PUT
![Page 30: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/30.jpg)
destroy
class EventsController < ApplicationController
def destroy Event.find(params[:id]).destroy end...end
<%= link_to @event, event_path(@event), :method => :delete %>
the request method isDELETE
![Page 31: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/31.jpg)
4 HTTP methods, 4 URL helper, 7 actions
Helper GET POST PUT DELETE
event_path(@event)/events/1 /events/1 /events/1
events_path/events /events
edit_event_path(@event)/events/1/edit
new_events_path/events/new
show
index
edit
new
create
update destroy
![Page 32: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/32.jpg)
Singular and Plural RESTful Routes
• show, new, edit, destroy 是單數,對特定元素操作
• index, new, create 是複數,對群集操作
event_path(@event)
events_path
需要參數,根據 HTTP verb 決定 show, update, destroy
毋需參數,根據 HTTP verb 決定 index, create
![Page 33: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/33.jpg)
[custom route]_event[s]_path( event )
:method => GET | POST | PUT | DELETE
單數?複數?new, edit
除了_path 結尾,
_url 結尾則加上 http://domain/
![Page 34: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/34.jpg)
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
![Page 35: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/35.jpg)
PUT? DELETE?
![Page 36: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/36.jpg)
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>
![Page 37: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/37.jpg)
The Problem
• HTML spec only define GET/POST,so HTML forms don't support PUT/DELETE
• XmlHttpRequest spec (i.e. Ajax request) define at least support GET/POST/PUT/DELETE/HEAD/OPTIONS
• Firefox/Safari support
• Opera have no respond body if PUT/DELETE
• IE support except DELETE !!!!
![Page 38: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/38.jpg)
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.)
![Page 39: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/39.jpg)
TextThe type of request to make ("POST" or "GET"), default is "GET". Note: Other HTTP request methods, such as PUT and DELETE, can also be used here, but they are not supported by all browsers.
![Page 40: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/40.jpg)
4 HTTP methods, 4 URL helper, 7 actions
Helper GET POST PUT DELETE
event_path(@event)/events/1 /events/1 /events/1
events_path/events /events
edit_event_path(@event)/events/1/edit
new_events_path/events/new
show
index
edit
new
create
update destroy
It’s beauty, but RESTful can handle the real & complex world ?
![Page 41: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/41.jpg)
我想要加自己的 action 之問題一:
event has many attendees
![Page 42: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/42.jpg)
class Event < ActiveRecord::Base has_many :attendeesend
class Attendee < ActiveRecord::Base belongs_to :eventend
Model design
![Page 43: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/43.jpg)
nested resources(1)map.resources :events do |event| event.resources :attendees, :controller => 'event_attendees'end
預設的 controller 會是 attendees
<%= link_to ‘event attendees’, event_attendees_path(@event) %>
/events/2/attendees
class EventAttendeesController < ApplicationController
def index @attendees = Event.find(params[:event_id]).attendees end...end
![Page 44: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/44.jpg)
nested resources(2)<%= link_to ‘show’, event_attendees_path(@event,@attendee) %>
/events/2/attendees/3
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]) endend
Q: 為什麼不這樣寫?? Attendee.find(params[:id])
Ans: Scope Access
![Page 45: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/45.jpg)
Deep Nesting?Resources should never be nested more than one level deep.
![Page 46: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/46.jpg)
我想要加自己的 action 之問題二:
event memberships
![Page 47: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/47.jpg)
class Event < ActiveRecord::Base has_many :memberships has_many :users, :through => :membershipsend
class User < ActiveRecord::Base has_many :memberships has_many :events, :through => :membershipsend
class Membership < ActiveRecord::Base belongs_to :event belongs_to :userend
Model design
![Page 48: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/48.jpg)
map.resources :memberships
class MembershipsController < ApplicationController # POST /memberships?group_id=2&user_id=1 def create end # DELETE /memberships/3 def destroy endend
RESTful design 1
![Page 49: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/49.jpg)
map.resources :groups do |group| group.resources :membershipsend
class MembershipsController < ApplicationController # POST /group/2/memberships/?user_id=1 def create end # DELETE /group/2/memberships/3 def destroy endend
RESTful design 2
![Page 50: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/50.jpg)
我想要加自己的 action 之問題三:
event has one map
![Page 51: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/51.jpg)
singular resource route• 一般來說,resources 皆為複數,例如對群集操作
• 但也可以定義單數的 resourcemap.resources :events do |event| event.resource :map, :controller => ‘event_maps’end
map.resources :events
RESTful 的 controller 一定都是複數結尾
![Page 52: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/52.jpg)
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| %>
![Page 53: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/53.jpg)
我想要加自己的 action 之問題四:
operate event state(open/closed)
![Page 54: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/54.jpg)
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 %>
關
開
![Page 55: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/55.jpg)
why not
這要看你怎麼想“a separate resource” or “an attribute of event”
TextPUT closed=1 to /events/2
![Page 56: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/56.jpg)
我想要加自己的 action 之問題五:
search event
![Page 57: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/57.jpg)
Extra Collection Routes
map.resources :events, :collection => { :search => :get }
class EventsController < ApplicationController def search @events = Event.find_by_keyword(params[:keyword]) endend
<%= link_to ‘search’, search_events_path, :keyword => ‘osdc’ %>
![Page 58: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/58.jpg)
我想要加自己的 action 之問題六:
a event dashboard
![Page 59: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/59.jpg)
Extra Member Routes
map.resources :events, :member => { :dashboard => :get }
class EventsController < ApplicationController def dashboard @event = Event.find(params[:id]) endend
<%= link_to ‘dashboard’, dashboard_event_path(event) %>
![Page 60: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/60.jpg)
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.
![Page 61: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/61.jpg)
我想要加自己的 action 之問題七:
sorting event
![Page 62: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/62.jpg)
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’ %>
![Page 63: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/63.jpg)
我想要加自己的 action 之問題八:
event admin
![Page 64: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/64.jpg)
namespace map.namespace :admin do |admin| admin.resources :events end
# /app/controllers/admin/events_controller.rbclass Admin::EventsController < ApplicationController before_filter :require_admin
def index .... end end
![Page 65: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/65.jpg)
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.
![Page 66: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/66.jpg)
# 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('/') endend
map.resource :session
使用者登入 => 建立 session
![Page 67: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/67.jpg)
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.
![Page 68: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/68.jpg)
• 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.
Considerations(3)
![Page 69: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/69.jpg)
map.resources :attendees
map.resources :registers
class AttendeeController < ApplicationController
before_filter :manager_required
def show @person = @event.attendees.find(params[:id]) end
end
1 attendee Model2 Resources related
(2 Controller)
class RegistersController < ApplicationController
before_filter :login_required
def show @person = current_user.registers.find(params[:id]) end
end
for event manager
for attendeeing user
![Page 70: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/70.jpg)
[namespace]_[custom route]_[parent resource]_event[s]_path( [p,] e)
:method => GET | POST | PUT | DELETE
new, edit或客製?
單數?複數?有無 nested
![Page 71: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/71.jpg)
conclusion
![Page 72: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/72.jpg)
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
![Page 73: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/73.jpg)
not yet...
![Page 74: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/74.jpg)
respond_to你要什麼格式?
![Page 75: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/75.jpg)
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 } endend
![Page 76: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/76.jpg)
format.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>
<!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>
![Page 77: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/77.jpg)
def show_html @users = User.find(:all)end
def show_xml @users = User.find(:all) render :xml => @user.to_xmlend
def show_json @user = User.find(:all) render :json => @user.to_jsonend
you don't need this!
![Page 78: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/78.jpg)
只需定義一個 action減少重複的程式碼
Don’t repeat yourself
![Page 79: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/79.jpg)
更多 formats
• format.html
• format.xml
• format.js
• format.json
• format.atom
• format.rss
• format.csv
• format.xls
• format.yaml
• format.txt
• more....
![Page 80: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/80.jpg)
http://registrano.com/events/5381ae/attendees
http://registrano.com/events/5381ae/attendees.xls
http://registrano.com/events/5381ae/attendees.csv
![Page 81: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/81.jpg)
在原有的架構上新增不同格式的支援
(甚至是不同 UI 介面)
Adobe Flex
XML APIJSON API
![Page 82: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/82.jpg)
Rails: how to know?
![Page 83: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/83.jpg)
根據 URLhttp://localhost:3000/users.xml
<%= link_to ‘User List’, formatted_users_path(:xml) %>
在 template 中可以這樣寫
<a href=”/users.xml”>User List</a>
產生
![Page 84: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/84.jpg)
根據 HTTP request Headers
GET /users HTTP/1.1
Host: localhost:3000User-Agent: Mozilla/5.0 (Macintosh; U; Intel Mac OS X; zh-TW; rv:1.8.1.13)
Gecko/20080311 Firefox/2.0.0.13Accept: text/javascript, text/html, application/xml, text/xml, */*Accept-Language: zh-tw,en-us;q=0.7,en;q=0.3Accept-Encoding: gzip,deflateAccept-Charset: Big5,utf-8;q=0.7,*;q=0.7Keep-Alive: 300Connection: keep-aliveX-Requested-With: XMLHttpRequestX-Prototype-Version: 1.6.0.1
通常透過 Javascript 發送 Ajax request 時,加以設定。
![Page 85: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/85.jpg)
• 根據 params[:format] 參數,例如
GET /users/1?format=xml
![Page 86: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/86.jpg)
• 直接在 Controller code 中設定,例如class ApplicationController < ActionController::Base
before_filter :adjust_format_for_iphonehelper_method :iphone_user_agent?
protected
def adjust_format_for_iphonerequest.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"
endend
![Page 87: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/87.jpg)
自訂格式custom format
http://localhost:3000/mp3s/1.mp3
# config/initializers/mime_types.rbMime::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 } endend
![Page 88: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/88.jpg)
template如何產生這些格式?
![Page 89: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/89.jpg)
template
• format (minetype) 與 template generator (renderer) 是兩回事
• Rails2 的慣例是 action.minetype.renderer例如 filename.html.erb
![Page 90: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/90.jpg)
template 的慣例命名
def index @users = User.find(:all) respond_to do |format| format.html # index.html.erb format.xml # index.xml.builder endend
![Page 91: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/91.jpg)
erb template• 內嵌 ruby code
• 最常用來生成 HTML (即format.html)
<h1><%= @event.name %></h1>
<h1>OSDC 2008</h1>
show.html.erb
![Page 92: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/92.jpg)
builder template
• 用 Ruby 產生 XML
show.xml.builder
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>
![Page 93: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/93.jpg)
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| entry.title(event.title) entry.content(event.description, :type => 'html') entry.author do |author| author.name( event.creator.nickname ) end end end end
index.atom.builder
![Page 94: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/94.jpg)
Attentions for Rails 1.x developer
• filename.rhtml 變成 filename.html.erb
• filename.rxml 變成 filename.xml.builder
• 雖然變囉唆,但彈性更棒!!
![Page 95: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/95.jpg)
Ajax on Rails
![Page 96: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/96.jpg)
<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”></div>
Browser
Server
Ajax 請求 回應 format.html <h1>ABC</j1><ul>
<li>1</li><li>2</li>
</ul>
最簡單的 Ajax 用法
把 #content 的內容換成傳回來的
HTML 內容
<% =link_to ‘Terms’, terms_path, :update => ‘content’ %>
![Page 97: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/97.jpg)
注入腳本到瀏覽器執行的 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> Browser
Server
回應 format.js $("#content").html(ʻ blahʼ);$(“#sidebar”).html(ʻ blahʼ);$("#content").effect("highlight");
執行傳回來的Javascript 腳本
Ajax 請求
![Page 98: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/98.jpg)
RJS template
• 用 Ruby 來產生 Javascript
# show.rjs.jspage.replace_html ‘content’, :partial =>’note’page.visual_effect :highlight, ‘ content’
try { new Element.update("content", "blah"); new Effect.Highlight("content",{});} catch (e) { alert('RJS error:\n\n' + e.toString()); alert('new Element.update(\"content\", \"blah\");\nnew Effect.Highlight(\"content\",{});'); throw e }
def show @note = Note.find(params[:id]) respond_to |format| format.js endend
<%= link_to_remote ‘ajax’, :url => note_path(@note) %>
產生 Browser 執行 Server 傳回來的 Javascript code
![Page 99: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/99.jpg)
inline RJSdef 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
} endend
Write raw JavaScript
![Page 100: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/100.jpg)
js.erb template
• Write JavaScript directly
• Rails 1.x 需要 hack!(google MinusMOR plugin)
<%=link_to_remote ‘ajax’, :url => posts_path %>
def index ... respond_to |format| format.js endend
# index.js.erb $j("#foo").html(<%= (render :partial => 'note.html').to_json %>);$j("#foo").Highlight();
![Page 101: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/101.jpg)
jQuery on Rails• We love jQuery
• script/plugin installhttp://ennerchi.googlecode.com/svn/trunk/plugins/jrails
gugod hlb
byebye! Prototype.js
![Page 102: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/102.jpg)
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 endend
respond_to 的另個好處:支援 Graceful Degradation
<a href=”/users” onclick=”$.ajax(...blah...);return false;”>
Browser支援 JavascriptBrowser 不支援 Javascript
![Page 103: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/103.jpg)
so, what’s REST style?
![Page 104: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/104.jpg)
Nouns
Verb Content Types
URL
finite HTTP methods HTML, XML, JSON....etc
the resource have many representations
URL without action
![Page 105: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/105.jpg)
正題講完了,來換話題:
Front-end optimization
![Page 106: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/106.jpg)
Question: 網站放國外,連線速度很慢...
![Page 107: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/107.jpg)
Asset Caching
• fewer request
• merge JavaScript & CSS files
<%= stylesheet_link_tag "layout","basic","base", :cache => true %># => public/stylesheets/all.css
<%= stylesheet_link_tag "layout","basic","base","admin" :cache => "admin" %># => public/javascripts/admin.css
<%= javascript_include_tag "jquery","jquery-ui","jquery-fx","jrails","application", :cache => true %># => # public/javascripts/all.css
![Page 108: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/108.jpg)
Asset Caching(cont.)<link href="/stylesheets/blueprint/lib/reset.css?1193302860" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/blueprint/lib/typography.css?1193302860" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/blueprint/lib/grid.css?1193302860" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/blueprint/plugins/buttons/buttons.css?1193302860" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/blueprint/plugins/css-classes/css-classes.css?1193302860" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/stickies.css?1190808294" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/facebox.css?1203995080" media="screen" rel="stylesheet" type="text/css"><link href="/stylesheets/main.css?1206452830" media="screen" rel="stylesheet" type="text/css"><script src="/javascripts/jquery.js?1206433332" type="text/javascript"></script><script src="/javascripts/jrails.js?1206433332" type="text/javascript"></script><script src="/javascripts/facebox.js?1204792223" type="text/javascript"></script><script src="/javascripts/nicEdit/bkLib.js?1206450862" type="text/javascript"></script><script src="/javascripts/nicEdit/nicConfig.js?1206450862" type="text/javascript"></script><script src="/javascripts/nicEdit/nicEdit.js?1206450862" type="text/javascript"></script><script src="/javascripts/application.js?1206440609" type="text/javascript"></script>
<link href="/stylesheets/all.css?1206812340" media="screen" rel="stylesheet" type="text/css"> <script src="/javascripts/all.js?1206450935" type="text/javascript"></script>
服用 :cache => true
![Page 109: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/109.jpg)
JS minification
• Compress Javascript using bundle_fu plugin
<% bundle do %> ... <%= javascript_include_tag "prototype" %> <%= stylesheet_link_tag "basic.css" %> <%= calendar_date_select_includes "red" %> <script src="javascripts/application.js" type="text/javascript"></script> ... <% end %>
![Page 110: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/110.jpg)
GZIP compression
• add this to your Apache VirtualHost section:
# deflate_moduleAddOutputFilterByType DEFLATE text/html text/xml text/plain text/css application/x-javascript text/javascript;BrowserMatch ^Mozilla/4 gzip-only-text/htmlBrowserMatch ^Mozilla/4\.0[678] no-gzipBrowserMatch \bMSIE !no-gzip !gzip-only-text/html
![Page 111: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/111.jpg)
Add expires Header
• add this to your Apache VirtualHost section:
<Directory "/your_rails/public"> FileETag none ExpiresActive On ExpiresDefault "access plus 1 year"</Directory>
![Page 112: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/112.jpg)
Asset Servers
• Browser is limited to make only two connections to any single domain.
# Enable serving of images, stylesheets, and javascripts from an asset serverconfig.action_controller.asset_host = "http://asset%d.example.com"
http://asset0.example.comhttp://asset1.example.comhttp://asset2.example.comhttp://asset3.example.com
google ”HTTP 連線管理”
![Page 113: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/113.jpg)
Asset Servers
HTML
CSS JS
PNG
Server
![Page 114: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/114.jpg)
• High Performance Web Sites:Essential Knowledge for Front-End Engineers
• YSlow Firefox extensionhttp://developer.yahoo.com/yslow/
![Page 115: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/115.jpg)
Session in Rails
![Page 116: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/116.jpg)
Session in Rails(1)
• Rails 1.x, default is filesystem-based session
• easy configure
• Poor performance
• Not scale, difficult to maintain
• Crashing halt if thousands of session files
![Page 117: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/117.jpg)
Session in Rails(2)• we have ActiveRecord-based session
• can scale
• query DB every rquest
• purge session records regularly
ruby script/generate session_migrationrake db:migrate
config.action_controller.session_store = :active_record_store
![Page 118: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/118.jpg)
Session in Rails(3)
• Rails2’s default is cookie-based session
• easy configure
• performance
• scale
• limited to 4k
config.action_controller.session = { :session_key => '_my_app_session', :secret => 'some_really_long_and_hashed_key' }
enough for user ID and flash message
![Page 119: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/119.jpg)
REST end.(不知道還剩多少時間?)
![Page 120: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/120.jpg)
Bonus:
Write your rake
![Page 121: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/121.jpg)
rake• 依照 dependence 順序執行任務
• rake -T
• write your rake in /lib/tasks/foo.rake
task(:a => [:b, :c] ) do # do some thing end
rake a excute task b, task c first
![Page 122: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/122.jpg)
desc "Send latest announment mail to all users" task(:send_emails => :environment) do # Find users to email User.find(:all).each do |user| puts "Emailing #{user.name}" UserNotifier.deliver_latest_announcement(user) end end
task :environment do require(File.join(RAILS_ROOT, 'config', 'environment'))end
example 1: “rake send_emails”
![Page 123: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/123.jpg)
namespace :dev do
desc "Rebuild system" task :build => ["tmp:clear","db:drop", "db:create", "db:migrate", :setup, :fake] desc "Setup system data" task :setup => :environment do puts "Attempts to create system user" u = User.new( :login => "root", :password => ‘password’ ) u.save! end
desc "Create fake data" task :fake => :environment do Event.create!( :title => 'osdc 2008' ) Event.create!( :title => 'osdc 2009' ) Event.create!( :title => 'osdc 2010' ) ... ... end end
example 2: “rake dev:build”
![Page 124: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/124.jpg)
namespace :dev do
desc "Rebuild system" task :build => ["tmp:clear","db:drop", "db:create", "db:migrate", :setup, :fake] desc "Setup system data" task :setup => :environment do puts "Attempts to create system user" u = User.new( :login => "root", :password => ‘password’ ) u.save! end
desc "Create fake data" task :fake => :environment do Event.create!( :title => 'osdc 2008' ) Event.create!( :title => 'osdc 2009' ) Event.create!( :title => 'osdc 2010' ) ... ... end end
example 2: “rake dev:build”
![Page 125: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/125.jpg)
namespace :dev do
desc "Rebuild system" task :build => ["tmp:clear","db:drop", "db:create", "db:migrate", :setup, :fake] desc "Setup system data" task :setup => :environment do puts "Attempts to create system user" u = User.new( :login => "root", :password => ‘password’ ) u.save! end
desc "Create fake data" task :fake => :environment do Event.create!( :title => 'osdc 2008' ) Event.create!( :title => 'osdc 2009' ) Event.create!( :title => 'osdc 2010' ) ... ... end end
example 2: “rake dev:build”
![Page 126: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/126.jpg)
other usage
• cron 定期執行,例如產生報表
• loop { do_some_thing; sleep 5;} end一個簡單的 daemon
• Avoid Heavy Response Processing
![Page 127: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/127.jpg)
Bonus:
Capistrano
![Page 128: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/128.jpg)
自動化 deploy 步驟1. ssh to production server2. svn checkout 3. run some your script (link file/copy config file/ clear cache…etc)
4. restart mongrel cluster
![Page 129: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/129.jpg)
/releases/r956
/shared/log
/shared/tmp
/current/
/shared/upload/
/shared/config/database.ymlln -s
ln -s
/releases/r955
/releases/r954
/releases/r953
/releases/r952
svn checkout
“cap deploy”
Rails app
目錄結構
![Page 130: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/130.jpg)
/releases/r956
/shared/log
/shared/tmp
/current/
/shared/upload/
/shared/config/database.ymlln -s
ln -s
/releases/r955
/releases/r954
/releases/r953
/releases/r952
svn checkout
“cap deploy”
/releases/r957
Rails app
目錄結構
![Page 131: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/131.jpg)
cap deploy
![Page 132: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/132.jpg)
another choice:
Vlad
![Page 133: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/133.jpg)
Bonus:
Facebox Render plugin
![Page 134: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/134.jpg)
Facebox• Facebox is a JQuery-based lightbox
http://famspam.com/facebox/
![Page 135: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/135.jpg)
Rails 無縫使用 Facebox
Text
class ApplicationController < ActionController::Base include FaceboxRenderend
<%= facebox_link_to "Login", :url => login_url %>
def new # do some thing you want respond_to do |format| format.html format.js { render_facebox } endend
![Page 136: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/136.jpg)
<% form_remote_tag :url => batch_event_attendees_path(@event) do %>
Ajax form submit
![Page 137: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/137.jpg)
def batch ... respond_to do |format| format.html format.js { render_to_facebox } endend
batch.html.erb
Text
![Page 138: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/138.jpg)
Usage
render_facebox #default is action_name.html.erb
render_facebox :template => 'other.html.erb' render_facebox :action => :index render_facebox :partial => 'foo.html.erb' render_facebox :html => '<p>bar</p>'
Source code: http://github.com/ihower/facebox-render/
Blog: http://handlino.com/blog/2008/02/26/57/
gem install facebox-render & unpack it
![Page 139: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/139.jpg)
Bonus:
SPAkit plugin
![Page 140: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/140.jpg)
Transform existed website to single page application (SPA)所有的操作皆為 Ajax request,不 reload 頁面
![Page 141: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/141.jpg)
Ajax update #content
![Page 142: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/142.jpg)
<%= spakit_link_to( "Login" , :url => new_session_path ) %>
def new respond_to do |format| format.html end
end
![Page 143: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/143.jpg)
Usage
<%= spakit_link_to 'new person', :url => new_person_path %>
<%= spakit_form_for @person, :url => people_path %>
Source code: http://github.com/ihower/spakit/
Blog: http://handlino.com/blog/2008/02/17/52/
gem install spakit & unpack it
![Page 144: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/144.jpg)
Really Simple History (RSH): Ajax history and bookmarking library
![Page 145: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/145.jpg)
Reference books:
• Rails Way (Addison Wesley)
• Advanced Rails (Pragmatic)
• Code Review PDF (peepcode.com)
• Rails2 PDF (peepcode.com)
• RESTful Web Services (O’REILLY)
![Page 146: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/146.jpg)
thank you.
![Page 147: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/147.jpg)
Q: 用 Rails 接不到案子怎麼辦?
![Page 148: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/148.jpg)
Acts as ASP.NETscript/plugin install http://actsasaspdotnet.googlecode.com/svn/trunk/acts_as_aspdotnet
![Page 149: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/149.jpg)
<form action="/people" class="new_person" id="new_person" method="post"> <p> <b>Name</b><br /> <input id="person_name" name="person[name]" size="30" type="text" /></p>
<p> <b>Email</b><br /> <input id="person_email" name="person[email]" size="30" type="text" /></p></form>
<form action="/People/Default.aspx" class="new_person" id="new_person" method="post"> <input id="__EVENTTARGET" name="__EVENTTARGET" type="hidden" value="" /> <input id="__EVENTARGUMENT" name="__EVENTARGUMENT" type="hidden" value="" /> <input id="__VIEWSTATE" name="__VIEWSTATE" type="hidden" value="/XtplIo7SVYvjZC8ffNqtkHIhP5TdNKRLNnFL5mTJuprao/NDMrAzOXmYnpUv56K0gBNK+sN0yT5EJsxU+BtzhGUEb6Pmn5u1wGQHm4ntORTpCZ1mPGkaQ5cgs6jbuOC21lQcb68SkVH0h3EDyx6PCn3tkg4+BgVfm/hOj4U1520V81VVPoJLnmuTrhUZ+GRvbTR7btLYWqCUozv2Da9yROdQmUGD6PohHm+/es3kSQLgXH+EWYee9EaHW2dyTNm46YhRVuHgbCHkko5kI+7bwyNmtrUT70h2OqOYFiU2whPf0z7e9iK3OxfuCqxV8vW1MULKv4QldC6sla/ZQ1HdlxBr/wwvTIEQkN6bCm92DgKEQNZT5T+W5pQV2NHugb9p/d2VFN+poEvet3nNvq5693qsgOR7BOxiXIc2vhDmI7KkB/iXos6obvs/X+WX1llJkgzfCezhlNCTBoBheGhy69cGz8doRxqzId9BFdaI8Y4Ng+HgRgFLWcqdEat34dv2OzhxSJn4Svv=" />
<p> <b>Name</b><br /> <input id="Page11__ctl1_person_name" name="person[name]" size="30" type="text" /> </p>
<p> <b>Email</b><br /> <input id="Page12__ctl8_person_email" name="person[email]" size="30" type="text" /> </p></form>
Viewstate
![Page 150: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/150.jpg)
Beautiful Error Pages
![Page 151: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/151.jpg)
map.resources :people
/People/Default.aspx/People/Default.aspx
/People/1/Show.aspx /People/1/Show.aspx /People/1/Show.aspx
/People/New.aspx /People/1/Edit.aspx
.aspx URL
![Page 152: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/152.jpg)
Meta tag
<%= aspdotnet_includes %>
<meta name="vs_showGrid" content="False"><meta name="GENERATOR" Content="Microsoft Visual Studio 7.0"><meta name="CODE_LANGUAGE" Content="C#"><meta name="vs_defaultClientScript" content="JavaScript"><meta name="vs_targetSchema" content="http://schemas.microsoft.com/intellisense/ie5">
![Page 153: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/153.jpg)
<input id="person_name" name="person[name]" size="30" type="text" />
<input id="Page17__ctl3_person_name" name="person[name]" size="30" type="text" />
Element ID
![Page 154: RESTful Rails2](https://reader034.fdocument.pub/reader034/viewer/2022051411/5412bd528d7f720a4e8b46a3/html5/thumbnails/154.jpg)
end.(真的沒有了)