rmosolgo / rmosolgo/graphql-ruby
[PRO] Pundit authorization for a mutation creating a new record
@rmosolgo is already working on this.
Since Dec 2, 2019.
- Dominant language
- Ruby
- Stars
- 5.4k
- Forks
- 1.4k
- Avg merge
- 23h 19m
- Merged PRs (30d)
- 28
Description
I have another Pundit integration question. This relates to authenticating a create mutation. (I've had good look with authenticating input arguments and update, thanks to your help. See this example for what I mean)
With an update mutation there is a record instance to check the policy against based on the :id argument that loads the record instance; however, with a create, all we have is an Input object that has not yet turned into a record instance or been created.
class NotePolicy < ApplicationPolicy
# An admin can create a note on behalf of someone else;
# everyone else can only create their own notes
def create?
person.admin? || record.person == person
end
end
class Mutations::NoteCreate < Mutations::BaseMutation
type Types::NoteType
pundit_role nil # Anyone can call the mutation at this point
class NoteInput < Types::BaseInputObject
argument :comment, String, required: true
argument :person_id, ID, required: true
end
argument :input, NoteInput, required: true
# NOTE: what I would would like to be adding to this :input argument call
# would be something like a --> pundit_role: :create
# but that requires initializing a new object from the input kwargs
def resolve(input:)
# not authorization happening at this point
Note.create!(input.to_kwargs)
end
end
The first pundit_role nil allows anyone to call the mutation, which is what we want; it's really the NoteInput that I would like to attach the pundit_role: :create too ... kind of like how it can be done in the update example linked above.
But in order for that to happen, NoteInput needs to initialize Note.new before it can check the :create?.
I imagined that to play this out manually in the resolve method it would look something like this:
def resolve(input:)
note = Note.new(input.to_kwargs)
Pundit.authorize(current_user, note, :create?)
note.save!
note
end
This authorizes things correctly, but the raised error doesn't get handled the same way as it would if we were using pundit_role: :create at the mutation, argument, or type level.
Am wondering if you have a recommendation for how to approach this?
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.