能力:条件依赖对象(allow :create only for team_members)
Ability: conditions dependent on the object (allow :create only for team_members)
设置
一个基本的酒店设置,其中 users
是 hotel
的团队成员。它使用 cancancan and devise 和 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
。 users
到 hotels
.
反之亦然
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
[...]
Problem/Question
在某个视图中我有这段代码:
<% 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
。
解决这个问题的最佳方法是什么?显然 link 不应该显示,而且 /hotels/:hotel_id/check_ins/new
URL 应该 不 可以被任何不是团队成员的人访问。
试试这个:
can [:create], CheckIn if user.team_memberships.present?
或
can [:create], CheckIn if user.hotels.present?
希望对您有所帮助。
这是一个常见问题,这是 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
设置
一个基本的酒店设置,其中 users
是 hotel
的团队成员。它使用 cancancan and devise 和 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
。 users
到 hotels
.
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
[...]
Problem/Question
在某个视图中我有这段代码:
<% 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
。
解决这个问题的最佳方法是什么?显然 link 不应该显示,而且 /hotels/:hotel_id/check_ins/new
URL 应该 不 可以被任何不是团队成员的人访问。
试试这个:
can [:create], CheckIn if user.team_memberships.present?
或
can [:create], CheckIn if user.hotels.present?
希望对您有所帮助。
这是一个常见问题,这是 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