Alexander Popov
Alexander Popov

Reputation: 24905

How to implement role-based authorization to only specific attributes of a model in Rails?

I have an Accounts resource (model + controller). Currently, all actions of the AccountsController are preceded by the authorize_admin before_action, which checks if a user is an admin or not and if not - it redirects the user to the home_path.

What I now want to do is allow the users to edit some fields of their own accounts. I am not sure how to do this. I have several ideas:

  1. In the same Accounts controller create custom edit_personal_account and update_personal_account actions, with a custom personal_account_params (Rails 4, strong parameters). In the personal_account_params I will permit only the fields that a user is allowed to edit.

  2. Create a new PersonalAccounts controller with normal restful actions, but only edit, update, and show. This controller will interact again with the Account model.

  3. Use a gem like cancancan or pundit. I have skimmed over their documentation and wikis, but so far I have only found examples of how to restrict access to whole actions based on role and not how to restrict access to specific fields.

So my question is - which of the three ways would be most appropriate for my scenario and are there any other better ways?

Upvotes: 2

Views: 931

Answers (1)

nicohvi
nicohvi

Reputation: 2270

How about something like this?

# accounts_controller.rb
before_action :authorize_admin, except: [:edit, :update]

def update
  @account.update(account_params)
end

private

def account_params
  if current_user.admin?
    params.require(:account).permit(<all params>)
  else
    params.require(:account).permit(<subset of params>)
  end 
end

This way you would explicitly declare in your account_params method which parameters normal users would be able to edit, which may or may not be what you want.

You would also need to hide some of the fields in your edit view based on the current user's role (i.e. if she's an admin, hide nothing etc.), but that shouldn't be very hard. You could even create a custom form builder doing so.

Upvotes: 6

Related Questions