1

I'm working on Authorization for my school assignment, which is a Reddit clone. I was just introduced to the Pundit Gem for Authorization on user roles, ie, Admin, Moderator, Member and Guest.

I have to make it so:

Admins and Moderators should see all posts, members should only see their own posts, and guests should see no posts.

Sign in as a normal user, and you should only see the posts you've created.

application_policy.rb

class ApplicationPolicy
  attr_reader :user, :record

  def initialize(user, record)
    @user = user
    @record = record
  end

  def index?
    false
  end

  def show?
    scope.where(:id => record.id).exists?
  end

  def create?
    # Checks if user exists and is logged in
    user.present?
  end

  def new?
   create?
  end

  def update?
    # Checks if user is logged in, the owner or admin
    user.present? && (record.user == user || user.admin?)
  end

  def edit?
    update?
  end

  def destroy?
    update?
  end

  def scope
    record.class
  end
end

Here is what I am working on:

This will check if a user is present, and if the user is a moderator or administrator and only grant them access to view posts. Works just like the instructions state.

post_policy.rb

class PostPolicy < ApplicationPolicy
  def index?
    user.present? && (user.moderator? || user.admin?) 
  end
end

Now if I look back at my application_policy.rb I can see this line here, "Checks if the user is logged in, the owner, or admin":

user.preset? && (record.user == user || user.admin?)

If I try to add this into my authorization of index? I will keep getting a

"NoMethodError in PostsController#index"

class PostPolicy < ApplicationPolicy
  def index?
    user.present? && (user.moderator? || user.admin? || record.user == user) 
  end
end

Thank you.

Community
  • 1
  • 1
Jonathan Musso
  • 1,374
  • 3
  • 21
  • 45

1 Answers1

5

Use scopes: https://github.com/elabs/pundit#scopes

In your case PostPolicy.rb should look like this:

class PostPolicy < ApplicationPolicy
  def index?
    true
  end

  class Scope
    attr_reader :user, :scope

    def initialize(user, scope)
      @user = user
      @scope = scope
    end

    def resolve
      if user.admin? || user.moderator?
        scope.all
      else
        scope.where(user: user)
      end
    end

  end

end
lazzi
  • 435
  • 4
  • 12
  • Thank you kindly for your response. While this solution works, is there a way to achieve this same result with how I was attempting to implement this feature? – Jonathan Musso May 01 '15 at 19:54
  • It should be possible, but you would have to iterate over list of posts you fetched from DB and check policy for each of them. And then remove those that should not be accessible by user. Easier and recomended solution is to use scope and then in your controller simply call @posts = policy_scope(Post). – lazzi May 01 '15 at 20:21
  • for others reading this, the scope policy is enforced by calling @records = policy_scope(Record) in the controller – sakurashinken Sep 12 '18 at 22:30