CanCan Rails如何限制用户阅读他们没有创建的数据

时间:2016-01-25 05:45:43

标签: ruby-on-rails controller authorization cancan cancancan

我在Rails 3.2应用程序中使用CanCan 1.6.1。我在控制器中使用authorize_resource来限制用户:read, :create, :update: and :delete的内容。

在我的V2Posts controller中,authorize_resource来电不适用于:show行动。

在我的能力档案中,我试图限制用户只阅读自己的帖子。没有错误,但不幸的是,他们可以查看其他用户的帖子。

class V2PostsController < ApplicationController
  layout 'panel_layout', only: :show
  before_filter :redirect_if_existing, only: [:new, :create]

  authorize_resource

  def show
    @v2_post = V2Post.find(params[:id], include: :user_updates)
    @organization = @v2_post.organization

    respond_to do |format|
      format.html
      format.js
    end
  end
  ...
end

ability.rb:

class Ability
  include CanCan::Ability

  @user = nil

  def initialize(user)
    alias_action :taco,
                 :sandwich,
                 to: :read

    @user = user

    if user.is_in_role?(:admin)
      can :manage, :all
    else
      default_rules

      user.roles_list.each do |role|
        meth = :"#{role}_rules"
        send(meth) if respond_to? meth
      end
    end
  end

  def default_rules
    cannot [:read, :create, :update, :destroy], :all
    ...
  end

  def pro_user_rules
    can :read, V2Post, proid: @user.id
  end
...
end

模型/ v2_post.rb:

class V2Post < ActiveRecord::Base
  attr_accessible :proid, :user_updates_attributes, :organization

  belongs_to :user,  :foreign_key => "proid"
  has_many :user_updates, as: :pro_post, dependent: :destroy
  accepts_nested_attributes_for :user_updates

end

load_and_authorize_resource致力于阻止用户查看其他用户&#39;帖子。但是,它为我加载资源,还为其他操作添加了额外的数据库调用。不应该authorize_resource为我的案子工作吗?我在show动作中明确定义了@ v2_posts(自己加载资源)。为什么没有传递给authorize_resource电话?

  • 我想避免要求额外调用数据库
  • 我不想自动加载资源以进行自定义操作
  • 我想授权每个CRUD操作。

鉴于此,load_and_authorize_resourceauthorize_resource中的哪一个效果更好,每个的优点/缺点是什么?我已经阅读了文档,我很困惑。

1 个答案:

答案 0 :(得分:0)

问题在于authorize_resource作为前置过滤器运行,并且在调用authorize_resource之后才会在操作内部设置实例。当实例为nil时,authorize_resource方法默认授权类V2Report。授权该类忽略属性条件(例如,可以:读取V2Report,user_id:@ v2_post.user_id)。

您可以使用load_and_authorize资源,并让CanCan在每个操作之前在控制器中设置实例变量。对于以更复杂的方式加载资源的操作(如V2Post.find(params[:id], include: :user_updates)),您可以创建自定义prepend_before_filter方法,以便为某些操作加载资源。只要这是前置的,那个加载的实例将被传递给authorize_resource方法。如果实例已经加载,load_and_authorize_resource将不会对数据库进行额外调用。

class V2PostsController < ApplicationController
  prepend_before_filter :custom_load_resource, only: [:show, :edit]
  load_and_authorize_resource

  def show
    render @v2_post
  end

  private

  def custom_load_resource
    @v2_post = V2Post.find(params[:id], include: :user_updates)
  end

end

您也可以完全忘记load_resource,并在100%的时间内使用您自己的before_filter。或者,您可以放弃过滤器并从操作中调用authorize!。在我最近的经验中,上面详述的方法很适合RESTful控制器。