What Good are Strong Parameters?

What Good are Strong Parameters?

Will Warner
Will Warner

April 05, 2014

There are already several eloquent web postings available explaining the Strong Parameters feature of Rails 4. In this post I’ll provide my take on one problem Strong Parameters solve and why moving to them for the sake of this problem alone is worth the trouble.

Mass Assignment in Rails 2

Back in the dark ages, when it must have been hard to imagine why anyone would use a website maliciously, Rails 2 provided the convenience of setting several attributes on a model en masse. The view would collect a hash of parameters and pass it to the controller. The controller would pass that same hash, usually without modification, to the model, which in turn would use the parameters to create or update an instance of the model.

Blacklisting and Whitelisting in Rails 3

Once the vulnerability of mass assignment became obvious, Rails came up with a way of protecting model attributes. One could add an attr_protected declaration to the model, and then give the list of attributes which could not be changed by mass assignment. This was called blacklisting, since it presumed all attributes were accessible unless specified otherwise.

When the drawbacks of blacklisting became obvious, Rails then moved to whitelisting. This meant presuming that no attributes are accessible unless specified in the model with attr_accessible.

One difficulty with whitelisting was that for the model to have different levels of accessibility, you would need an attr_accessible declaration for each level. Additionally, the controller would need logic to set these different levels (e.g. an admin vs. a normal user) to be passed along to the model.

Strong Parameters in Rails 4

This latest version of Rails gets rid of both attrprotected and attraccessible. It still uses whitelisting, but this has been moved out of the model, leaving the model closer to its ideal state as a simple facade into ActiveRecord. Before passing parameters into the model, they need to be wrapped in a call to permit. Any parameter not strengthened through this call generates ActiveModel::ForbiddenAttributesError

Through several of my own cluttered implementations I have learned that the more logic you have in a model, the more difficult it is both to test and to modify. Specifying attr_accessible in a model is a merely more subtle way of introducing a conditional: if the parameter is in this list, go ahead and assign it; otherwise throw an error. The conditional gets even more intricate with levels of accessibility: if the role is A, give this access; otherwise if…

Moving conditionals into the controller is not ideal either, but there are at least two ways to permit different parameters for different roles. One is to have separate controllers, e.g. an AdminController and a UserController. These could modify the same (User) model, but with their own levels of access.

Another approach is to delegate the behavior controlling access into its own object. The controller would let this object determine which parameters are cleared for modifying the model. Naturally, testing this object will be far simpler than putting a model with myriad attr_accessible declarations through its paces.

Strong Parameters force us to take logic out of the model. This is always a good thing. Maybe for Rails 5, we’ll continue to simplify and get rid of controllers.