Nick Kallen's blog
Access Control is a simple idea. We want company employees to be able to delete inappropriate content; but random Users cannot. Here I propose one way to implement Access Control that has the particular advantage of being very general, very concise, and unlikely to be violated. I call it RESTful Access Control.
One of the issues in my previous post The Controller Action that sparked some interest is the handling of the creation of multiple Models in one Action. In this post I shall elaborate on this problem in some detail, first considering the cases where in constructing the Dependent Object no data are needed from the querystring/params, and secondly where such data are necessary (and where we have a complicated nested Form). Let's head right in to an example.
With No Extra Params to Worry About
Your site has Groups and Memberships. Our Business Rule is: when a user creates a Group, she should also be a Member of that Group. Following the Controller Formula, we know the solution in advance:
class GroupsController < ActionController::Base
def create
group = logged_in_user.groups.build(params[:group])
raise SecurityTransgressionError.new unless logged_in_user.can_create?(group)
if group.save
...
end
end
end
This leaves unresolved where to put our Business Rule...
When I introduce a programmer to Rails I encourage them to read the article Skinny Controller, Fat Model. My only complaint about this article is that it applies the Skinny/Fat Pattern in a vague way, proceeding as if by intuition. I've found instead that there is a formulaic way to produce excellent Controller code--the Controller Formula
Skinny/Fat: Code Complexity vs. Abstraction Boundaries vs. The Formula
The Skinny/Fat pattern is typically stated in terms of Lines of Code. Your Controllers should have few Lines of Code; where there are many, move them to the Model. This rule has more exceptions than it has applications, so we can state the intent of the Pattern more precisely in terms of Abstraction Boundaries. Remove all Business Logic from your Controllers and put it in the model. Your Controllers are only responsible for mapping between URLs (including other HTTP Request data), coordinating with your Models and your Views, and channeling that back to an HTTP response. Along the way, Controllers may do Access Control, but little more. These instructions are precise, but following them requires intuition and subtle reasoning. The purpose of this post is to avoid subtle heuristics like Abstraction and Code Complexity. There is a Formula. Let's see an example that follows the Formula:
def create
model = Model.new(params[:model])
raise SecurityTransgressionError.new unless logged_in_user.can_update?(model)
if model.save
render ...
else
...
end
end
What's going on here? The Action channels user input to the model. It raises an Exception if the user lacks permission to perform this Action. Validation is performed by the model. Given the results, the Controller renders the appropriate Template to the HTTP Response.







