The following blog post contains material either currently found or soon to be incorporated into my new book, "Easy Active Record for Rails Developers". Among many other topics, you'll learn about model generation, migrations, validations, associations, scopes, joins, includes, forms integration, nested forms, and model testing with RSpec and FactoryGirl. The book is now available, head over to this website's home page to learn more.


Longtime Rails users are undoubtedly familiar with the attr_accessible macro. It is used in conjunction with a Rails model to explicitly identify the model attributes that can be set using mass-assignment. For instance, to identify the Location model’s name, description, city and zip attributes as mass-assignable, you would set attr_accessible within the Location model like this:

class Location

  attr_accessible :name, :description, :city, :zip

end

With attr_accessible set like so, I can now conveniently mass-assign these attributes:

location = Location.new(
                   :name => 'Arcade Legacy', 
                   :description => 'Offers more than one dozen arcade classics!', 
                   :city => 'Cincinnati', 
                   :zip => '45240')

Were the name, description, city, and zip parameters coming from a properly configured form, assignment is even easier:

location = Location.new(params[:location])

In either case, both approaches are preferable to manually setting each attribute like so:

location = Location.new
location.name = 'Arcade Legacy'
location.description = 'Offers more than one dozen arcade classics!'
location.city = 'Cincinnati'
location.zip = '45240'

As is demonstrated by these examples, the attr_accessible macro is indeed useful. But what if the model included an additional Boolean attribute called approved that an administrator would use to confirm the submitted arcade was indeed worth of inclusion? If you added approved to the attr_accessible list, then a cunning arcade operator could inject params[:location][:approved] into the POSTed form and bypass the official approval process. At the same time, opting to omit the approved attribute from the attr_accessible declaration means you’ll need to resort to a less efficient solution for coding the administrative interface’s new and update actions differently (notably, using the latter approach involving manually setting each attribute separately).

Enter Rails 4 and Strong Parameters

Ever the pragmatists, the Rails development team removed this inconsistency in Rails 4, deprecating attr_accessible (and its’ sibling attr_protected) in preference of a new feature known as strong parameters. This approach moves the burden of whitelisting to the controller, allowing you to whitelist attributes within the context in which they will be used, rather than requiring a global whitelisting within the model.

To use strong parameters you’ll typically want to define a private method within the desired controller:

class LocationController < ActionController::Base

  def new
  end

  def create
  end

  def edit
  end

  def update
  end

  private

  def location_params
    params.require(:location).permit(:name, :description, :city, :zip)
  end

end

The params.require method identifies the required parameter, in this case location. The permit method identifies the list of allowed parameter keys, in this case name, description, city, and zip. With the location_params method defined, you can use it both within your create and update methods. I’ll next create simplified create and update methods to demonstrate use of the private location_params method:

class LocationController < ActionController::Base

  def create
    @location = Location.create(location_params)
  end

  def update
    location = Location.find(params[:id])
    location = Location.update_attributes!(location_params)
    redirect_to location
  end

  private

  def location_params
    params.require(:location).permit(:name, :description, :city, :zip)
  end

end

So returning to our original problem, how would you provide the administration controller with the ability to mass-assign the approved attribute? That’s right, you’ll just add a customized version of the location_params method to the appropriate controller:

  def location_params
    params.require(:location).permit(:name, :description, :city, :zip, :approved)
  end

Once in place, you’re free to code the create and update methods in the same manner as above, foregoing the need for any additional customized coding.

In a later post I’ll talk about advanced strong parameters features, such as the ability to whitelist nested parameters.


Like what you read? There’s plenty more where this came from in my new book, “Easy Active Record for Rails Developers”!

Comments