我在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
电话?
鉴于此,load_and_authorize_resource
和authorize_resource
中的哪一个效果更好,每个的优点/缺点是什么?我已经阅读了文档,我很困惑。
答案 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控制器。