Search code examples
ruby-on-railsrubyruby-on-rails-5pundit

Create Pundit Policies to API controller methods


How to create Policies for API-Controller's using Pundit gem?

Api controller path: /app/controllers/api/posts_controller.rb

#posts_controller.rb

class Api::PostsController < ApplicationController

  def create
  ......
  end


  def update
  ......
  end

  def delete
  ......
  end

end

I have Controller for the same and the corresponding Model

controller path: /controllers/posts_controller.rb

#posts_controller.rb

class PostsController < ApplicationController

  def create
  ......
  end


  def update
  ......
  end

  def delete
  ......
  end

end

I have created the policies for posts controller. How to create the same for API's Controller


Solution

  • Pundit is resource-based, not controller-based. When you call authorize and pass it a resource, Pundit cares about the action name and the resource type, but it does not care about the controller name.

    Regardless of whether you call from the Api::PostsController:

    # /app/controllers/api/posts_controller.rb
    
    class Api::PostsController < ApplicationController
    
      def create
        @post = Post.find(params[:post_id])
        authorize @post
      end
    end
    

    or from your original PostsController:

    # /app/controllers/posts_controller.rb
    
    class PostsController < ApplicationController
    
      def create
        @post = Post.find(params[:post_id])
        authorize @post
      end
    end
    

    So long as @post is a member of the Post class, you can call authorize @post from the controller of a parent or child or a completely unrelated controller, it doesn't matter. In all cases Pundit will go and look for a method called create? within app/policies/post_policy:

    # app/policies/post_policy.rb
    
    class PostPolicy < ApplicationPolicy
    
      attr_reader :user, :post
    
      def initialize(user, post)
        @user = user
        @post = post
      end
    
      def create?
        user.present?
      end
    end