Rails and CanCan: Authorization for Specific Fields

Andy Lindeman

2 min read

Feb 23, 2012

Rails and CanCan: Authorization for Specific Fields

A recent project we worked on at Highgroove involved scheduling events on a calendar. These events had a lifecycle of “statuses,” such as “pending approval” and “approved.”

All users were able to set the “status” to values such as “pending approval,” but only certain privileged users could move them to states such as “approved.”

We were already using CanCan for authorization, but there was no built-in facility for authorizing field-level changes. There were workarounds in certain cases, such as using custom actions, but none of these fit with our specific use case.

Read on for how we modeled the problem and used a Plain Old Ruby Object (PORO) to keep things clean.

We wanted to route edits to an event, including status changes, through the EventsController#update action because users could edit both the status and other attributes from the same #edit view.

We really wanted to avoid code that looked like below:

It might make sense for the controller to enforce the authorization, but it did not make sense to us for the code to perform the authorization to appear in-line within the controller.

At some point we realized that we could create a Plain Old Ruby Object (PORO) to model the “event status change” and then use the facilities that CanCan already provided to authorize the change.

First, we created an EventStatusChange class in lib/event_status_change.rb; note that this class has no Rails dependencies.

(Astute readers may have noticed that EventStatusChange could be implemented as a one-liner using Struct)

Next, we added code to the Ability class where CanCan authorization code normally lives:

Finally, we did have to keep some code in the controller, but it looks much cleaner:

We are not completely sure this is the best way to approach the problem, but it seemed pretty reasonable to us at the time. While not shown here, many of the pieces can be tested in isolation with external objects as stubs; we also found that ability to be a big win.

Have you ever tried to authorize changes to specific fields in Rails? If so, how did you approach it?

Mark Dalrymple

Reviewer Big Nerd Ranch

MarkD is a long-time Unix and Mac developer, having worked at AOL, Google, and several start-ups over the years.  He’s the author of Advanced Mac OS X Programming: The Big Nerd Ranch Guide, over 100 blog posts for Big Nerd Ranch, and an occasional speaker at conferences. Believing in the power of community, he’s a co-founder of CocoaHeads, an international Mac and iPhone meetup, and runs the Pittsburgh PA chapter. In his spare time, he plays orchestral and swing band music.

Speak with a Nerd

Schedule a call today! Our team of Nerds are ready to help

Let's Talk

Related Posts

We are ready to discuss your needs.

Stay in Touch WITH Big Nerd Ranch News