Is there a consensus best approach to implementing user roles when using RESTful resource routes?
Say I have the following resources:
User has_many Tickets
Event has_many Tickets
Ticket belongs_to Person, Event
And then further say I have two types of Users: customers and agents. Both will log into the system, but with different resource access and functionality based on their roles. For example:
Customers can access:
Agents can access:
Which of the 4 general approaches below will be cleaner and more flexible?
Separate controllers within role folders and resources in namespaces, eg:
namespace "agent" do
resources :events, :tickets, :people
end
namespace "customer" do
resources :events, :tickets, :people
end
Separate controllers by role, eg:
AgentController
def sell_ticket, etc
CustomerController
def buy_ticket, etc
Shared controllers with separate actions where needed, eg:
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
Shared actions with conditional statements, eg:
TicketController
def create
if @role == :customer
#buy ticket
elsif @role == :customer
#sell ticket
end
end
These operations stand for four possible actions, known as CRUD: Create, Read, Update and Delete. The server sends the data to the client in one of the following formats: HTML. JSON (which is the most common one thanks to its independence of computer languages and accessibility by humans and machines)
I would suggest using a combination of the last two proposed implementations. They adhere to RESTful representation, they put authorization at the appropriate level (controllers), and it is a scalable implementation.
REST is, essentially, about accessing nouns with verbs. So you want Agents and Customers to perform actions (verbs) in relation to Tickets, Users, and Events (nouns). In order to accurately represent these nouns you should have a controller for each. Customers can then identify the resource they are looking for by the URL, http://example.com/events/22
. From here you can use Rails' routing to represent context for various resources, ie http://example.com/events/22/tickets
by doing something like:
resource :events do
resource :tickets
end
By adhering to a RESTful architecture, you are buying into the end to end principle. The paradigm for representing objects needs to be only responsible for that. It shouldn't try to authenticate. That isn't its job. Authorization should happen in the controllers. I would highly recommend looking into gems like CanCan or Declarative Authorization that set all of this up for you.
Finally, this model scalable. By keeping authorization separate from the representation of your resources you only have to use it if you need it. This keeps your application light, flexible, and simple.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With