authorize with a parent resource in Pundit

517 views Asked by At

I have a Campaign model which has many Applicants. I'm currently nesting Applicants within Campaigns. I'm trying to authorize a user to applicants#index based on if they are the owner of the campaign.

  resources :campaigns do
    ..
    resources :applicants do
      ..
    end
  end

What's the best way to secure the applicants#index action in Pundit? Ideally I would like to pass the @Campaign to authorize.

class ApplicantsController < ApplicationController
    def index
        @applicants = Applicant.where(campaign: @campaign)

        authorize @campaign
        respond_with(@applicants)
    end

But this results in Pundit looking for campaign_policy.

1

There are 1 answers

3
deefour On BEST ANSWER

I'd probably use the show? method on the CampaignPolicy

authorize @campaign, :show?

where show? (call it whatever you want...manage?, etc...) would be

def show?
  record.user_id = user.id
end

Just because the resource being displayed is a list of applicants doesn't mean you need to authorize against them directly. If your logic requires authorizing the owner of the campaign, do that.

Finally, if this is some wide-spread, common thing in your application, you might consider creating some value object to wrap your current user and campaign in.

class CurrentState < Struct.new(:user, :campaign); end

and then override the pundit_user method.

def pundit_user
  CurrentState.new(current_user, Campaign.find(params[:campaign_id])
end

See Additional Context in the Pundit docs.