能力:取决于对象的条件(仅允许 :创建team_members)



Setup

基本的酒店设置,usershotel的团队成员。它使用Cancancan,并使用Rails 5.2进行设计

rails g scaffold User name
rails g scaffold Hotel name
rails g scaffold TeamMembership user:references hotel:references
rails g scaffold Reservation starts_on:date ends_on:date hotel:references
rails g scaffold CheckIn hotel:references reservation:references

hotels通过has_many :users, through: :team_memberships连接到users。反之亦然,usershotels.

config/routes.rb

resources :hotels do
resources :reservations
resources :check_ins
end

app/controllers/check_ins_controller.rb

class CheckInsController < ApplicationController
before_action :authenticate_user!
load_and_authorize_resource :hotel
load_and_authorize_resource :check_in, :through => :hotel
[...]

app/models/ability.rb

[...]
can [:read, :destroy], CheckIn, hotel_id: user.hotel_ids
can [:create], CheckIn
[...]

问题/疑问

在视图中的某个地方,我有以下代码:

<% if can? :create, CheckIn %>
<%= link_to 'Create Check-In', new_hotel_check_in_path(@hotel) %>
<% end %>

它应该只对@hotel的团队成员可见。

ability.rb的第一行工作正常,但第二行不起作用,因为任何人都可以创建一个新check_in但只有team_memberships应该能够为他们的酒店创建一个新check_in

解决这个问题的最佳方法是什么?显然,不应显示链接,但非团队成员的任何人都不应访问/hotels/:hotel_id/check_ins/newURL。

这是一个常见问题,这就是business逻辑与authorization逻辑相交的地方。

关于这个问题有很多意见。

1(许多人认为这种交集是不可接受的。他们会建议您以这种方式做您需要的事情(分离业务和授权逻辑(

<% if can?(:create, CheckIn) && current_user.member_of?(@hotel) %>
<%= link_to 'Create Check-In', new_hotel_check_in_path(@hotel) %>
<% end %>

2(如果你确定你需要这个,你可以这样做:

Hotel模型添加新权限:

can [:check_in], Hotel do |hotel|
user.member_of?(hotel)
end

然后在视图中:

<% if can?(:create, CheckIn) && can?(:check_in, @hotel) %>
<%= link_to 'Create Check-In', new_hotel_check_in_path(@hotel) %>
<% end %>

在控制器中:

class CheckInsController < ApplicationController
# ...
def new
authorize! :check_in, @hotel
# ...
end
end

试试这个:

can [:create], CheckIn if user.team_memberships.present?

can [:create], CheckIn if user.hotels.present?

希望这有帮助。

相关内容

最新更新