0

I'm having a hard time understanding strong params. I understand it prevents mass assignment of variables you don't permit. But in Hartl's tutorial I also read that without strong params someone could change for example any user's admin status through a patch request (which I guess isn't mass assignment, because that's just one value your would change). But then how do you implement strong params for variables that:

  • Should only be allowed to be set once (when creating a new user)
  • Some users should be able to change but others not

For example, I have:

  private
    def user_params
      params.require(:user).permit(:email,
                                   :username,
                                  #:verified,
                                  #:admin,
                                  #:moderator,
                                  #:activated, 
                                  #:activated_at, 
                                   :password, 
                                   :password_confirmation)
    end

Now, the ones with a dash I understand should NOT be permitted. Otherwise users could change their values through mass assignment (or otherwise).

However:

  • An admin user (which is a specific user from the same table/controller) should be able to change these variables for all users.
  • In the case of my app, organizations (a different table) should be able to give a user moderator rights and thus change these values for users.
  • Username should only be set when a new user is created and after that should never be permitted to change. Now, by permitting username in strong_params doesn't that mean it is vulnerable to be changed through mass assignment?

How does strong params relate to these issues?

Nick
  • 3,496
  • 7
  • 42
  • 96
  • I haven't ever dealt with this, but my opinion from my experience: the `user_params` could have a conditional that checked for the `current_user`s permissions, and set the `permit`ted attributes based on that conditional. – Mike Manfrin Apr 13 '15 at 19:09
  • As for changing the username, I'd manage that in the model, or have a `new_user_params`. – Mike Manfrin Apr 13 '15 at 19:11

2 Answers2

0

I'm no expert but as far as I can figure out: When you set up strong parameters you are typically controlling what gets passed into an update_attributes/create method. So you are defining what survives within:

params[:user][ ... ]

In the case of an admin updating a user, you don't need to POST a whole user object, you can simply make a call to a particular function that will change whichever user attributes you want to change. In other words:

$.ajax(
  { "method": "PUT", "url": "/users/" + uid },
  { "task": "make_admin" }
);

And in your controller:

def update
  if params[:task] == "make_admin" && user_is_authorized
    User.find(params[:id]).admin = true
  end
end
jcuenod
  • 55,835
  • 14
  • 65
  • 102
0

While the simplest case is for user_params to always do the same thing and be used by all calls to update_attributes that is just the simplest case.

It is perfectly sensible to permit based on the privileges of the current user or to have different permit lists for different actions (so maybe only the permit list used in the create action permits :username).

Another pattern you could consider is an Admin namespace for those with administrative access: Admin::UsersController would allow more fields to be mutated and might expose more functionality or data that a normal user should not have access to.

Frederick Cheung
  • 83,189
  • 8
  • 152
  • 174
  • So it would be save to define in the controller a `def edit` with an `if` statement where it sets @users based on a different `strong params` if its an admin and `else` uses a second more strict `strong params` version. That is, there's no need for define two different `def edits`, this can be done through an if else statement? – Nick Apr 14 '15 at 09:40
  • @Nick sounds fine in principal – Frederick Cheung Apr 14 '15 at 10:14