So I'm using the Pundit gem to allow/disallow users to access routes, and it's working fine for that. I have a certain requirement where for users, both admin and non-admin can create a user, but only admin can restrict a user(Users are restricted by setting restricted_at to DateTime.now).
So the #create and #update actions are allowed to be accessed by both admin/non-admin, but it's the specific attribute I want to authorize.
My options are:
- I could just create the model, but nil the restricted_at(if set), if the user is non-admin
class UserPolicy
def create?
@record.assign_attributes({restricted_at: nil}) unless @user.admin?
return true
end
end
But I don't think this is the best way to do it. I'd much rather return an error here. However if I try to add an error like @record.errors.add(:restricted_at, "can only be set by admin")
, then later in the controller when save is called, it'll revalidate, and since the models validations don't validate who is changing something.
So is there way to do this with Pundit? What makes the most sense from a user/UX perspective? - Return a 401 Unauthorized if a non-admin tries to create a user with restricted_at set, or update the attribute on an existing user. I personally think this is bad because the users isn't unauthorized for the route, just for the model. And a blanket 401 doesn't explain WHY. - Create the model, but just nix anything a non-admin does to that attribute, like I do above - Some alternate where I either add a model error with Pundit(if possible) or in the controller(less ideal, i'd rather keep all the validation/permission stuff in the model or pundit. If I put logic in the controller, then I'll have validations in three places, the model, the controller, and pundit, which seems smelly to me)
Just to make it clear, those are the possibilites, but what I want, and what I think is best, is to NOT create the model (if a non admin sets the retricted_at on create), and return an error message.
How can I sort this out? Thanks.