使用Cancan 的限制:RESTful controller (resource)
一般新進開發者會被 cancan 這兩個 API 搞得七葷八素:load_and_authorize_resource
、authorize_resource
。
這是因為 cancan 並沒有明顯的在 README 上做出說明:cancan 在使用上是有架構的限制:
* 必須為 RESTful resource
(cancan 直接假設了你一定使用 RESTful,畢竟這年頭誰還在寫 non-RESTful …?)
* resource 必須與 Controller 同名
(@article 與 ArticlesController)
使用過 cancan 的人,大概都「猜到」規則好像是這樣?
其實不必猜,source code 裡面就寫的很清楚。
load_and_authorize_resource
load_and_authorized_resource 做了兩件事:
- load_resource
- authorize_resource
load_resource 作什麼呢?: loard_resource => load_resource_instance
okay,這段的作用等於如果你在 Controller 裡面下了 load_resource,cancan 會自作聰明的幫你 自動 在每一個 action 塞一個 instance 下去
如果是 new 這個 action,效果會等於
如果是 show 這個 action,效果會等於
有好處也有壞處,好處是…你不需要自己打一行 code,壞處就是不熟 cancan 的人,找不到 @article 在哪裡會驚慌失措…
load_resource
還有一些其他進階用法,在 controller_additions.rb 裡面有不少說明...
authorize_resource
authorize_resource 就是對 resource 判斷權限(根據 CanCan::Ability 裡的權限表)。
而這個 resource 必定是與同名的 instance。
如果是 ArticlesController 對應的必然是 @article。
但是你會想說這樣慘了?萬一我在 ArticlesController 裡面要用 @post 怎麼辦呢?
你可以在 controller 裡面指定 resource instance 的 name 要用什麼名字: authorize_resource :post
Ability 裡面要這樣下
resource 規則小結
所以 cancan 裡面的 resource 第一個會去吃 controller 的名稱當成 resource name,如果是 ArticlesController
,instance 就會是 @article
,而在 ability 裡面就會是 can :read, Article
。這是在假設你已經使用同名設計 resource & controller 的情況下。
如果非同名。你可以做出指定:authorize_resource :post
,雖然是 ArticlesController,但是這一組的 resource 名稱為 post
,所以 instance 就會是 @post
,而在 ability 裡面就會是 can :read, Post
。
一般開發者常會誤會的是
- ability 會綁到 model,實際上不是
- controller 名稱要與 @instance 名稱相同,實際上不一定
- @instance 要與 model 同名,實際上不用
- ability 吃的應該是 controller name,實際上不一定(吃的是 resource name,且可以被指定)。
Cancan 吃的是 resource,而且自作聰明的假設了大家「應該」都同名,而且 README example 也是使用「同名」,才會造成了這麼多的誤解…
如果你有更多疑問,可以直接看 source code 裡面的 這一支controller_resource.rb,相信會讓你對整個架構更加的清楚...
小結
這一節解釋了開發者認為最難懂的 load_and_authorize_resource
、authorize_resource
。下一節我們要來講 ability 要如何設計…