Why are `scope`-oriented actions (particularly `index` actions) treated differently in Pundit?

蓝咒 提交于 2019-12-21 04:11:24

问题


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?


回答1:


My understanding of authorization vs scopes in Pundit is as follows:

authorization: 'is this user allowed to act upon (create/update/destroy) this resource?'

within scope : 'should this user be able to see (index/show) this resource?'

Authorization (authorize @resource) defers to permitted_attributes in ResourcePolicy for the answer.

Scopes (policy_scope(Resource)) defer to resolve.

I believe the reasoning behind Pundit's scopes is that there should be only one location in your code where you define who should have access to what resources.

You could, as you've described, implement the same behavior in your controllers or your views. However, putting the code into a Policy guards against unauthorized access should you happen to forget to scope appropriately in one of your controller methods.

I think of policy_scope() as the way to restrict visibility, while other result refinements (e.g. sorting) can take place at the controller level. There's no doubt a lot of personal preference at play, however.



来源:https://stackoverflow.com/questions/21172620/why-are-scope-oriented-actions-particularly-index-actions-treated-differen

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!