我使用devise
和cancan
宝石并拥有简单的模型关联:user
has_many subscriptions
,subscription
belongs_to :user
。请关注SubscriptionsController
:
class SubscriptionsController < ApplicationController
load_and_authorize_resource :user
load_and_authorize_resource :subscription, through: :user
before_filter :authenticate_user!
def index
@subscriptions = @user.subscriptions.paginate(:page => params[:page]).order(:created_at)
end
#other actions
end
Cancan
Ability.rb
:
class Ability
include CanCan::Ability
def initialize(user)
user ||=User.new
can [:read], [Edition, Kind]
if user.admin?
can :manage, :all
elsif user.id
can [:read, :create, :destroy, :pay], Subscription, user_id: user.id
can [:delete_from_cart, :add_to_cart, :cart], User, id: user.id
end
end
end
问题在于我无法将subscriptions
操作用作用户,但可以作为管理员使用。并且UsersController
没有问题。当我从SubscriptionsController
删除以下行时:
load_and_authorize_resource :user
load_and_authorize_resource :subscription, through: :user
before_filter :authenticate_user!
完全没有问题。所以这些问题或Ability.rb
中的问题。有什么建议吗?
更新:有趣的是,如果我向html模板添加类似can? :index, Subscription
的smth,则会显示true
。如果添加can? :index, Subscription.first
(另一个用户的订阅)等smth,则会显示false
。看起来像Cancan
正常工作。但问题是什么?..
更新:如果更改SubscriptionsControlle
,请执行以下操作:
class SubscriptionsController < ApplicationController
#load_and_authorize_resource :user
#load_and_authorize_resource :subscription, through: :user
before_filter :authenticate_user!
def show
@user = User.find params[:user_id] #line 1
@subscription = @user.subscriptions.find params[:id] #line 2
@container_items = @subscription.container_items.paginate(:page => params[:page])
authorize! :show, @subscription #line 4
end
#some actions
end
它非常完美,可以在需要时防止未经授权的用户访问。 第1,第2和第4行不等于注释?..
更新:在routes.rb
中有以下内容:
resources :users, except: [:show] do
member do
get 'cart'
delete 'delete_from_cart' => 'users#delete_from_cart'
post 'add_to_cart' => 'users#add_to_cart'
end
resources :subscriptions do
member do
post 'pay'
end
end
end
更新:下一个解决方案可防止对index
以外的所有订阅操作进行未经授权的访问:
class SubscriptionsController < ApplicationController
load_resource :user
load_resource :subscription, through: :user
authorize_resource through: :current_user
before_filter :authenticate_user!
#actions
end
那么阻止访问index
行动的最佳方式是什么?
仅找到以下解决方案:
before_filter :authorize_index, only: [:index]
def authorize_index
raise CanCan::AccessDenied unless params[:user_id] == current_user.id.to_s
end
答案 0 :(得分:1)
应该是
load_and_authorize_resource :subscription
或只是
load_and_authorize_resource
在你的情况下,当你想要嵌套资源时,那么
load_and_authorize_resource :through => :current_user