Rails RESTful 制約即解放

DHH的投影片提到一個概念:

Constraints are liberating (a straight jacket for your mind)

這裡指的 Constraints (制約) 是什麼? 我想指的是 Controller 不出以下七種 action (註) :

class PeopleController < ActionController::Base
 # GET /people
 def index() end
 
 # GET /people;new
 def new() end
 
 # POST /people
 def create() end
 
 # GET /people/1
 def show() end
 
 # GET /people/1;edit
 def edit() end
 
 # PUT /people/1
 def update() end
 
 # DELETE /people/1
 def destroy() end
end 

例如多對多關係。我們以往習慣把加入或刪除關聯的動作放在 UsersController 或 GroupsController 中,如以下的程式碼 :

class Group < ActiveRecord::Base
 has_and_belongs_to_mang :users
end

class User < ActiveRecord::Base
 has_and_belongs_to_mang :groups
end

class GroupsController < ActionController::Base
 # POST /groups/1;add_user?user_id=2
 def add_user() end
 
 # POST /groups/1;add_user?user_id=2
 def remove_user() end
end

class UsersController < ActionController::Base
 # POST /users/1;join_group?group_id=2
 def join_group() end
 
 # POST /users/1;leave_group?group_id=2
 def leave_group() end
end

用制約的想法之後,我們得把加入或刪除關聯的動作獨立出來了,變成這樣:

class Group < ActiveRecord::Base
 has_many :memberships
 has_many :users, :through => :memberships
end

class User < ActiveRecord::Base
 has_many :memberships
 has_many :groups, :through => :memberships
end

class Membership < ActiveRecord::Base
 belongs_to :group
 belongs_to :user
end

class MembershipsController < ActionController::Base
 # POST /memberships?group_id=1&user_id=2
 def create() end
 
 # DELETE /memberships/3
 def destroy() end 
end

透過這樣的 CRUD 技法之後,除了開發時使用統一的風格來寫程式架構之外,意義在於 把對網站的所有操作都變成對某個 Resource (某個URL) 的 HTTP GET/POST/PUT/DELETE 操作 (註)。撰寫 Controller action 的同時也完成了 Web APIs (註),除了可以給使用者瀏覽器之外,我們也可以用 machine client 如 ARes 來操作整個 RESTful 網站系統的任一功能。這在以前幾乎是很花時間跟成本的事啊 : server-side 要特地打造 Web Service,client-side 也必須花時間學習如何使用API,現在只需要遵循 RESTful 可以從 SOAP and WS-* 解放出來… :p

Constraints are liberating 它讓我們更專注在要做什麼。

註: 你會發現 Controller 的這七個 action 中, GET /people;new 跟 GET /people/1;edit 這兩個只需對瀏覽器使用者有作用,所以沒有提供XML(不算是Web APIs)。另外五個 action ( GET /people, GET /people/1 跟 POST/PUT/DELETE) 則同時擔任了Web APIs 跟 回應瀏覽器 的功能。

參考資料:

參與討論

2 則留言

發佈留言

發表迴響