Hacker News new | past | comments | ask | show | jobs | submit login

Note: For the purposes of this discussion, "accessible" means "accessible via mass assignment". See http://news.ycombinator.com/item?id=3781317.

The change in Rails 3.2.3 that will likely affect the most people is a new default setting in config/application.rb for newly generated applications. By default, Active Record is now configured to throw exceptions any time an attribute not included in attr_accessible is included in a mass assignment:

    .
    .
    .
    module SampleApp
      class Application < Rails::Application
        .
        .
        .
        config.active_record.whitelist_attributes = true
        .
        .
        .
      end
    end
(Exactly what this means is explained below.)

The model generators have also been updated to include an attr_accessible line. Unfortunately, if you include all of the attributes in the call to rails generate at the command line, they will all be accessible by default, which kind of defeats the purpose. For example, if you type

    $ rails generate model User name:string admin:boolean
you'll get

    class User < ActiveRecord::Base
      attr_accessible :name, :admin
    end
which probably isn't what you want: chances are that the admin attribute shouldn't be accessible. To prevent security holes, I therefore strongly recommend writing explicit tests for all inaccessible attributes (see below).

To see the effects of the new default, consider a User model with an admin attribute not included in the attr_accessible list:

    class User < ActiveRecord::Base
      attr_accessible :name, :email, :password, :password_confirmation
      .
      .
      .
    end
With the new default configuration, code like

    User.new(admin: true)
will raise an

    ActiveModel::MassAssignmentSecurity::Error
exception. You can test for this (in RSpec) as follows:

    describe "accessible attributes" do
      it "should not allow access to admin" do
        expect do
          User.new(admin: true)
        end.should raise_error(ActiveModel::MassAssignmentSecurity::Error)
      end    
    end
For more details, see the latest version of the Ruby on Rails Tutorial (http://railstutorial.org/book?version=3.2).



Broken record:

Remember that attr_accessible does NOT mean attributes that the application can change. It does NOT mean attributes that have automatic setters and getters. Even if an attribute isn't listed in attr_accessible, you can still write controller code to work with the attribute!

What attr_accessible means is "attributes that can be changed via mass-assignment, through #update_attributes or #create". These are the attributes that you are allowing users to change without supervision.

Keep attr_accessible minimal. Avoid the temptation to list every attribute your application will allow users to change. You can always write line-by-line setters, like:

    u.role = params[:role] if role_safe?(params[:role])
If you don't keep your attr_accessible statements minimal, you can end up with mass-assignment problems even when you have whitelisting enabled.


Yep, and the new strong_parameters library from core team supports this and is a taste of things to come: moving towards consistently controller-based access-control. http://weblog.rubyonrails.org/2012/3/21/strong-parameters/


I am not, by the way, sold on this particular ideology about models and controllers. The controller-based pattern has stuff to recommend it, as does the model-based pattern. I think most apps are going to end up wanting to do both.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: