rmosolgo / rmosolgo/graphql-ruby

[PRO] Pundit authorization for a mutation creating a new record

Open
#2,625 4 comments 0 reactions 1 assignee View on GitHub

@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

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.