在使用RESTful资源路由时,是否存在实现用户角色的最佳共识方法?
说我有以下资源:
User has_many Tickets
Event has_many Tickets
Ticket belongs_to Person, Event
然后进一步说我有两种类型的用户:客户和代理商。两者都将登录到系统,但具有基于其角色的不同资源访问和功能。例如:
客户可以访问:
代理商可以访问:
以下4种一般方法中哪一种更清洁,更灵活?
角色文件夹中的控制器和命名空间中的资源,例如:
namespace "agent" do
resources :events, :tickets, :people
end
namespace "customer" do
resources :events, :tickets, :people
end
按角色分隔控制器,例如:
AgentController
def sell_ticket, etc
CustomerController
def buy_ticket, etc
共享控制器,在需要时具有单独的操作,例如:
TicketController
before_filter :customer_access, :only => :buy
before_filter :agent_access, :except => :buy
def buy #accessed by customer to create ticket
def sell #accessed by agent to create ticket
使用条件语句的共享操作,例如:
TicketController
def create
if @role == :customer
#buy ticket
elsif @role == :customer
#sell ticket
end
end
答案 0 :(得分:6)
我建议使用最后两个提议的实现的组合。他们遵循RESTful表示,他们将授权放在适当的级别(控制器),并且它是一个可扩展的实现。
REST本质上是关于accessing nouns with verbs。因此,您希望代理和客户执行与故障单,用户和事件(名词)相关的操作(动词)。为了准确地表示这些名词,你应该为每个名词配备一个控制器。然后,客户可以通过URL http://example.com/events/22
识别他们正在查找的资源。从这里你可以使用Rails的路由来表示各种资源的上下文,即http://example.com/events/22/tickets
做类似的事情:
resource :events do
resource :tickets
end
通过坚持RESTful架构,您将购买end to end principle。表示对象的范例只需要对此负责。它不应该尝试进行身份验证。那不是它的工作。授权应该在控制器中进行。我强烈建议您查看像CanCan或Declarative Authorization这样的宝石,为您设置所有这些。
最后,这个模型可扩展。通过将授权与资源表示分开,您只需在需要时使用它。这使您的应用程序轻松,灵活,简单。
答案 1 :(得分:0)
虽然他们都处理创建故障单,但代理/故障单销售与客户/故障单购买似乎与我不同,他们应该分开。最终它们可能会进一步分歧,因为它们的使用方式与开头的方式不同。
可以通过模块或从公共父控制器继承共享控制器功能:
module TicketsControllersCommom
# common helper methods
end
class TicketsController < ApplicationController
include TicketsControllersCommom
# actions
end
class AgentTicketsController < ApplicationController
include TicketsControllersCommom
# actions
end
我可能会将代理商部分视为一种管理部分,其中客户部分是默认部分:
/events/xx/tickets # collection
/events/xx/tickets/xx # member
# etc.
/events/xx/agent/tickets # collection
/events/xx/agent/tickets/xx # member
# etc.
或者,如果您有很多管理类型的东西,比如代理也管理事件,您可以命名整个部分:
/agent/events/xx/tickets
/agent/events/xx/edit
# etc.
答案 2 :(得分:-1)
如果您对客户和代理商票使用相同的模型,那么在控制器中处理它们的方式应该没有重大区别。因此,创建动作将始终如下:
@ticket = Ticket.new(params[:ticket])
if @ticket.save
redirect_to @ticket
else
render :action => "new"
end
但您的观点可以简单定制:
<% if customer? %>
Customer area.
<% else %>
Agent area.
<% end %>