0
votes

I have a similar situation to this question, which was already posted. Koraktor has asked

I'm using a simple model for user authorisation with two ActiveRecords User and Role User and Role have a HABTM relation to each other. . . Manually assigning roles with @user.roles or @user.role_ids works, but not the "magic" inside User#new or User#update_attributes.

Oleg suggested that

attr_accessible :role_ids

be added to the user model. This would allow mass assignment operators to update roles. However, he cautioned against using this approach because of security concerns.

I have a follow up question to Oleg's response -

In this situation, is there a recommended method to update roles without using mass-assignment?

Also, assuming

  1. you authenticate users,
  2. only allow administrators to CRUD users by putting a before_filter in the users_controller,

is mass-assignment of role_ids still a valid concern?

1

1 Answers

2
votes

Mass assignment is a feature of Rails provided for using less code for updating a model like this

Model.create(params[:model])
@model.update_parameters(params[:model])

instead of

@model.field1 = params[:model][:field1]
@model.field2 = params[:model][:field2]
...
@model.save

But with this feature, comes the risk of updating values which we dont intend. For example, if we want just field1, field2 and field3 to be updated by the user and you use update_parameters for mass assignment, there is a risk of updating field4, if one is passing model[user][field4]=some_value either from url or by any other ways. If we are explicitly assigning the fields in the code, we do not have this risk. But then we will have to set the values for each field(wherever we are updating or creating) which is not very productive.

So, for using the mass assignment feature, we have 2 options. First is attr_protected

attr_protected :field4

This will protect field4 from being saved from mass assignment from params[:model] even if it contains field4. For saving field4, we have to call the setter for field4 explicitly in the code(@model.field4 =). But, the problem with attr_protected is that Rails may provide some other attributes that we may not know for mass assignment. For example, if we define

has_many :model2s

in Model.rb, Rails will provide a method model2_ids= automatically and this can be accessed by mass assignment.(If we give model[model2_ids]= in the url, it will create associations, not intended at all). So, there is a chance of missing attributes like this while using attr_protected.

So, the recommended method is to use attr_accessible

attr_accessible :field1, :field2, :field3

This will make these fields open for mass assignment and all other attributes in the model not available for mass assignment. So, the recommended way is to make those attributes which we are providing in a form for users to edit as attr_accessible and all other parameters will be protected. But, while using this you have to make sure you have included all the attributes you need for edit as attr_accessible.

In your case, since you want the user to edit the role_ids and you are providing access to CRUD for admin users only, I think you can use attr_accessible :role_ids. The alternative would be to assign role_ids explictely like .role_ids = params[:user][:role_ids]. You should use this, if you have another form where you dont want the user to edit the role_ids.