1. Technology
You can opt-out at any time. Please refer to our privacy policy for contact information.

Mass Assignment

By

Mass Assignment

Mass assignment was an early problem with Ruby on Rails. Most controllers naively did something along the lines of some_object.update_parameters(params[:user]) trusting that the params hash would only contain the fields generated by the view. However, an attacker could insert extra fields, mangle the HTTP request or otherwise populate the form with whatever they want, allowing them to set fields not otherwise reachable. For example, on a form that's supposed to allow you to update your email address and other profile information allowing you to edit the is_admin boolean field, and that's a problem.

Rails 3 Solution: attr_accessible

The solution in Ruby on Rails 3.x was to provide an attr_accessible method in the model. It let you make a whitelist of parameters that could be accessed using mass assignment. Say you have a User model with (among other fields) a name, email and is_admin, your model might look something like this.


class User < ActiveRecord::Base
  attr_accessible :email, :name
end

And not only email and name are accessible via mass assignment. But there are problems with this. First, is this really something that belongs in the model? This is more of a user interface problem. Second, what if one set of forms (that the user sees) mass assigns to only the public fields but another form (that admins see) can access a different set of fields? This "protection" imposes a UI restriction that doesn't need to be there. So Rails 4 has a better way of doing this.

Rails 4 Solution

Mass assignment is dead. You can no longer naively throw parameters at your model and have it sort them out. You can no longer blindly accept form data and hope everything works. The params hash is actually of the type ActionController::Parameters and Rails 4 adds two new methods: permit and

require.

The require method tests for the presence of a single key, and if that key exists it will return that value. It's basically the index method, but raises an exception if the key isn't there. It should be used to access keys (such as params[:user]) instead of the index operator. If only to create more meaningful error messages.

The permit method returns a new ActionController::Parameters object with only the passed list of fields populated. For example, params[:user].permit(:email, :name) would be the equivalent of the previous Rails 3 example. This new ActionController::Parameters hash has a flag set that allows it to be passed down to the model, so mass assignment is only possible if you've whitelisted the fields you want.

But that's not DRY, is it? You'll be repeating that list of parameters all over the place. Not a problem, just put a private method in your controller that returns this array. A Rails 4 controller might look something like this.


class UsersController < ApplicationController
  def update
    @user = User.find(params[:id])
    @user.update_attributes(user_fields)
  end

  protected
  def user_fields
    params.require(:user).permit(:name, :email)
  end
end
  1. About.com
  2. Technology
  3. Ruby
  4. Ruby on Rails
  5. Ruby on Rails 4
  6. Mass Assignment

©2014 About.com. All rights reserved.