Rails 4 - Pundit - Scoped Policy for Index

Pundit Policy Scope for Has Many Through Relationship

This is the most valuable part of the error message:

SQLite3::SQLException: ambiguous column name: user_id

The ambiguous column name error can happen when the SQL result set has multiple columns with the same name. In this case the column is user_id.

The user_id column is on the wikis table and the collaborations table. Both of these tables are used in the SQL query.

Here's the SQL snippet causing the problem:

# DB can't figure out which table "user_id = 2" refers to:
WHERE (hide = 'f' or user_id = 2 or collaborations.user_id = 2)

We need to specify a table name prefix on that user_id column.

To do this, try changing this line in WikiPolicy from:

scope.joins(:collaborations)
.where("hide = :hide or user_id = :owner_id or collaborations.user_id = :collaborator_id", {hide: false, owner_id: user.id, collaborator_id: user.id})

to:

scope.joins(:collaborations)
.where("hide = :hide or wikis.user_id = :owner_id or collaborations.user_id = :collaborator_id", {hide: false, owner_id: user.id, collaborator_id: user.id})

Rails - with Pundit Scopes in policy

I dont have much experience with pundit, however by looking at documentation and your code the code I can see 2 things.

1 - You shouldnt use methods like show? inside your scope class.

inside your scope class, you should use only methods that returns a scope. the methods that returns boolean should be in the Policy level. But in your code I can boolean methods inside the scope class.

Instances of this class respond to the method resolve, which should return some kind of result which can be iterated over. For ActiveRecord classes, this would usually be an ActiveRecord::Relation.

from the docs

2 - Given that Scope are POROs (Plain Old Ruby Object) you can have more than one resolve methods (of course with a different name :)), because resolve is just a method name.

May be you can do something like

#policy
class ArticlePolicy < ApplicationPolicy
attr_reader :user, :scope

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

class Scope < Scope
def resolve
# some scope
end

def resolve_show
#scope for show action
# E.g scope.all
end
end

def show?
article.state_machine.in_state?(:publish) ||
user == article.user ||
article.state_machine.in_state?(:review) && user.org_approver || false
end
end

in your controller

#Articles controller
class ArticlesController < ApplicationController
...
def show
authorize Article
ArticlePolicy::Scope.new(current_user, Article).resolve_show
end
...
end

This should first authorize your show method with ArticlePolicy#show? and the scope from ArticlePolicy::Scope#resolve_show

Disclaimer: Untested code, use at your own risk ;)

Need help authorizing index action with Pundit

You can authorize against the model instead of an object.

The code

authorize Wiki

will trigger the index? action in your pundit policy without the user object. In addition, you can use a scope to filter the data on a another level https://github.com/varvet/pundit#scopes.

Rails - Pundit, how to show controller index only for not logged in users

I guess pundit is a bit the wrong approch here, since it is built for authorizing users on certain actions and not defining what you see when you are not logged in.

This is usually something I would solve with controller logic, maybe be redirecting all users to some other path, when they are logged in in a before_action.

You might still be able to do it in pundit though by using this method in a headless policy (
https://github.com/varvet/pundit/blob/master/README.md#headless-policies).

 def index?
user.blank?
end

Pundit authorization in index

class MyModelPolicy < ApplicationPolicy
class Scope < Scope
def resolve
if user.admin?
scope.all
else
raise Pundit::NotAuthorizedError, 'not allowed to view this action'
end
end
end
end


Related Topics



Leave a reply



Submit