I am writing with respect to https://github.com/elabs/pundit#scopes
I am under the impression that authorization should answer the question Are you allowed access to this resource?, i.e. a true
/false
answer. This is the case with all actions except index
, which, according to Pundit's docs, should return different ActiveRecord::Relation
's depending on who is asking. For example, an admin gets scope.all
, while a regular user gets scope.where(:published => true)
.
app/policies/post_policy.rb
class Scope < Struct.new(:user, :scope)
def resolve
if user.admin?
scope.all
else
scope.where(:published => true)
end
end
end
app/controllers/posts_controller.rb
def index
@posts = policy_scope(Post)
end
My reservation is that this is a slippery slope, and soon I will be adding presentation to the scopes (e.g. scope.all.order('created_at ASC')
) -- and it just feels weird doing so in an authorization policy.
Of course I could move that to the controller...
def index
@post = policy_scope(post)
if user.admin?
@post = @post.order( 'created_at ASC' )
end
end
...but is that the controller's job? And I don't think it would be right to add such a call to the view. So maybe it should be a model method?
What would you say are the pros/cons of doing the following instead?
app/controllers/posts_controller.rb
This keeps index
just like the other methods, with one call to authorize
, and one call to a model method.
def index
authorize(Post)
@posts = Post.index(current_user)
end
app/policies/post_policy.rb
This simply gives a true/false answer. Are you authorized? Yes or no.
def index?
user.admin? || user.regular_user?
end
app/models/post.rb
And in the model we can get as fancy as we like.
def self.index(user)
if user.admin?
Post.all.order('created_at ASC')
else
Post.where(user_id: user.id)
end
end
Thoughts?