attr_accessible seems to no longer work within my model.

What is the way to allow mass assignment in Rails 4?

4 Answers 11

up vote 430 down vote accepted

Rails 4 now uses strong parameters.

Protecting attributes is now done in the controller. This is an example:

class PeopleController < ApplicationController
  def create
    Person.create(person_params)
  end

  private

  def person_params
    params.require(:person).permit(:name, :age)
  end
end

No need to set attr_accessible in the model anymore.

Dealing with accepts_nested_attributes_for

In order to use accepts_nested_attribute_for with strong parameters, you will need to specify which nested attributes should be whitelisted.

class Person
  has_many :pets
  accepts_nested_attributes_for :pets
end

class PeopleController < ApplicationController
  def create
    Person.create(person_params)
  end

  # ...

  private

  def person_params
    params.require(:person).permit(:name, :age, pets_attributes: [:name, :category])
  end
end

Keywords are self-explanatory, but just in case, you can find more information about strong parameters in the Rails Action Controller guide.

Note: If you still want to use attr_accessible, you need to add protected_attributes to your Gemfile. Otherwise, you will be faced with a RuntimeError.

1 upvote
  flag
Thanks will accept in 5 – user2532974
1 upvote
  flag
The document didn't say that attr_accessible need to be removed. What will happen if we keep it? – lulalala
12 upvote
  flag
You'll get an error if you don't make some adjustments to your Gemfile. RuntimeError in MicropostsController#index 'attr_accessible' is extracted out of Rails into a gem. Please use new recommended protection model for params(strong_parameters) or add 'protected_attributes' to your Gemfile to use old one. – user
2 upvote
  flag
Really good explanation thanks! – calabi
5 upvote
  flag
Great explanation. It seems like in practice, though, this moves Rails away from fat model, thin controller, etc, and towards thin models, and really bloated controllers. You have to write all this stuff for every instance, it doesn't read nicely, and nesting seems to be a pain. The old attr_accessible/attr_accessor in the model system wasn't broken, and didn't need to be fixed. One blog post got too popular in this case. – rcd
upvote
  flag
I am wondering about the advantage of strong parameter compared to the old stuff, attr_accessible method in model. As rcd said here Rails follows fat model. With this strong parameter we have to write all the attributes that permits to go, in controller. This seems odd to me. Anyone please tell me why they decided to go with strong parameters? – Abhi
1 upvote
  flag
You don't have to handle permitted parameters in your controllers. In fact it's a violation of the single responsibility principle. Take a look at the following blog post edelpero.svbtle.com/strong-parameters-the-right-way – Pierre-Louis Gottfrois
3 upvote
  flag
So gimmiky & frequently changing apis, coupled with newfound pedantics waste many developer hours in yet another painful Rails upgrade :-( – Brian Takita
upvote
  flag
@Pierre-LouisGottfrois Good explanation! But what about when I have two deep leves with nested attributes? I mean the first nested attributes are indicated in the principal model's controller strong_params. But what if the nested model has also nested attributes for a third model? Where do I need to specify the attributes for this third model in order to be whitelisted? – Alex Ventura

If you prefer attr_accessible, you could use it in Rails 4 too. You should install it like gem:

gem 'protected_attributes'

after that you could use attr_accessible in you models like in Rails 3

Also, and i think that is the best way- using form objects for dealing with mass assignment, and saving nested objects, and you can also use protected_attributes gem that way

class NestedForm
   include  ActiveModel::MassAssignmentSecurity
   attr_accessible :name,
                   :telephone, as: :create_params
   def create_objects(params)
      SomeModel.new(sanitized_params(params, :create_params))
   end
end
1 upvote
  flag
When you use 'strong parameters' you filter parameters in controller layer, and i don't think that this is best idea for all applications. For me the best way to filter parameters is to use additional layer. And we can use 'protected_attributes' gem to write this layer – edikgat

We can use

params.require(:person).permit(:name, :age)

where person is Model, you can pass this code on a method person_params & use in place of params[:person] in create method or else method

1) Update Devise so that it can handle Rails 4.0 by adding this line to your application's Gemfile:

gem 'devise', '3.0.0.rc' 

Then execute:

$ bundle

2) Add the old functionality of attr_accessible again to rails 4.0

Try to use attr_accessible and don't comment this out.

Add this line to your application's Gemfile:

gem 'protected_attributes'

Then execute:

$ bundle

Not the answer you're looking for? Browse other questions tagged or ask your own question.