Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Authorise user to edit a particular field using Pundit in Rails

I'm running Pundit in my Rails app for authorisation. I seem to be getting the hang of it all but want to know how to restrict the edit or update actions to a certain field.

For example, a user can edit their user.first_name, user.mobile or user.birthday etc but can't edit their user.role. Essentially my logic is, let the user edit anything that's cosmetic but not if it is functional.

These fields should only be able to be edited by a user who has a 'super_admin' role (which I have setup on the user.rb with methods such as the below).

  def super_admin?
    role == "super admin"
  end

  def account?
    role == "account"
  end

  def segment?
    role == "segment"
  end

  def sales?
    role == "sale"
  end

  def regional?
    role == "regional"
  end

  def national?
    role == "national"
  end

  def global?
    role == "global"
  end 

I pretty much have a clean slate user_policy.rb file where the update and edit actions are the default

  def update?
    false
  end

  def edit?
    update?
  end

Maybe I am thinking entirely wrong about this and should just wrap a user.super_admin? if statement around the role field on the user show page but this feels wrong if I am only using that tactic for security.

like image 900
Jay Killeen Avatar asked Nov 04 '25 12:11

Jay Killeen


2 Answers

Use Pundit's permitted_attributes helper which is described on the gem's README page: https://github.com/elabs/pundit

# app/policies/post_policy.rb
class PostPolicy < ApplicationPolicy
  def permitted_attributes
    if user.admin? || user.owner_of?(post)
      [:title, :body, :tag_list]
    else
      [:tag_list]
    end
  end
end

# app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def update
    @post = Post.find(params[:id])
    if @post.update_attributes(post_params)
      redirect_to @post
    else
      render :edit
    end
  end

  private

  def post_params
    params.require(:post).permit(policy(@post).permitted_attributes)
  end
end
like image 117
jpw Avatar answered Nov 07 '25 09:11

jpw


In your views, you can limit what users can see based on their role.

User View

- if current_user.super_admin? 
  = f.select(:role, User.roles.keys.map {|role| [role.titleize.role]})
- else
  = user.role

And in the policy you can call the role of the user to make sure they are able to edit.

class UserPolicy
  attr_reader :current_user, :model

  def initialize(current_user, model)
    @current_user = current_user
    @user = model
  end

  def edit?
    @current_user.super_admin || @current_user == @user
  end
end
like image 24
AGirlThatCodes Avatar answered Nov 07 '25 08:11

AGirlThatCodes



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!