Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Difference between attr_accessible and strong parameters

I have just been doing a bit of reading on attr_accessor, attr_accessible and strong parameters at a few different locations:

Difference between attr_accessor and attr_accessible
How is attr_accessible used in Rails 4? http://edgeapi.rubyonrails.org/classes/ActionController/StrongParameters.html

And I am looking at mass assignment:

http://code.tutsplus.com/tutorials/mass-assignment-rails-and-you--net-31695

I can't get my head around the difference between attr_accessible and strong parameters. I am not 100% confident in my understanding of the subjects mentioned above so I could be missing something simple but I know they do a similar job.

However, what is the difference between attr_accessible and strong parameters? Are they just a different name for the same thing? Why did we move from one to the other?

Any info is appreciated.

like image 214
atw Avatar asked Jun 11 '15 15:06

atw


2 Answers

Strong parameters and attr_accessible are two different ways of adding security protections to the Rails "mass assignment" feature. Strong Parameters is the way that is prescribed by the current version of Rails.

"Mass assignment" is a convenient shorthand in Rails that allows you to set many properties of a model in a single statement.

For example, imagine you have a @user that you want to update with data from a form submission. Without mass assignment, you'd have to write tedious code like this:

@user.first_name = params[:user][:first_name]
@user.last_name = params[:user][:last_name]
@user.phone_number = params[:user][:phone_number]
...
@user.save

And on and on for every form field.

With mass assignment, all of that code becomes a single line:

@user.update(params[:user])

But, this is full of security holes. Since params contains whatever data was submitted by the browser, a malicious user could add data to that submission that you did not expect. For example, they could add is_admin=1 to the parameters. If you have an is_admin database column, then mass assignment just let the user upgrade to an administrator. Yikes!

This is where Strong Parameters comes in. With Strong Parameters, Rails will raise a ActiveModel::ForbiddenAttributesError if you try to do the naïve update(params[:user]). Instead, you need to be explicit about what parameters you expect from the browser submission, using the require and permit helpers that Strong Parameters provides. Like this:

def user_params
  # Note that :is_admin is not permitted!
  params.require(:user).permit(:first_name, :last_name, :phone_number)
end

...
@user.update(user_params)

I can't speak for the maintainers of Rails, but I like Strong Parameters because it is flexible. If I have multiple actions in the users controller that expect different parameters, I can easily describe using permit the parameters that should be allowed.

Or if I have different user roles that are allowed to update different attributes, then I can easily model those permissions. As @CV-Gate mentioned, you can even change these permissions at runtime, which is a powerful.

In short, the flexibility of Strong Parameters is due to the fact that you can define that user_params method anywhere, and however you like. You have the full power of Ruby and OO concepts to make it work the way you want.

What about attr_accessible?

Without going into too much detail (since this feature is no longer supported by Rails): instead of using the permit method, you would do something similar using an attr_accessible macro in the model itself, like this:

class User < ActiveRecord::Base
  attr_accessible :first_name, :last_name, :phone_number
  ...
end

So for simple cases, it works very similar to Strong Parameters; you just define the list of attributes in a different place.

However, since attr_accessible is strongly coupled with the definition of the model class, you lose a lot of flexibility. What if you have two different controller actions that need to do mass assignment for the same User model? Now you are stuck.

attr_accessor

The attr_accessor macro is built into Ruby and has nothing to do with Rails, mass assignment, or security. It just happens to have a similar name. :)

like image 55
Matt Brictson Avatar answered Sep 27 '22 16:09

Matt Brictson


attr_accessible has been deprecated in Rails 4 in favor of Strong Parameters.

Both are different approaches to the mass assignment problem but Strong Parameters is more flexible.

In example, you have an Usermodel with the attributes email:string and is_admin:boolean. You wish to allow the users to modify their email through a form but not the is_admin field.

In Rails 3 you should do:

attr_accesible :email

With this approach it's not possible for an user to modify is_admin because that attribute is protected.

One of the good things of Strong Parameters is that you could do the following in your controller:

def user_params
  if current_user.admin?
    params.require(:user).permit(:email, :is_admin)
  else
    params.require(:user).permit(:email)
  end
end

This way one admin user will be able to modify is_admin while a normal user won't.

This is just one example and not the best way to grant administrative permissions to an user but it's quite illustrative.

The main advantage of Strong Parameters is that they are defined in the controller and can be dynamically assigned in run time. attr_accessible was a more static and monolithic way to whitelist attributes.

On the other hand attr_accessor is completely different thing and still can be used in Rails 4, in example, if you need one attribute in your model that it's not necessary to persist or to be written into the database but you require it in a form. Think about:

attr_accessor :has_accepted_legal_terms

It's a Ruby method that can be used to declare an attribute of your model that is not related to the database, an attribute of a Class or PORO (plain old ruby object).

like image 24
CV-Gate Avatar answered Sep 27 '22 18:09

CV-Gate