我将cancancan gem与Rails 5.2一起使用。
rails g scaffold User first_name email:uniq
rails g scaffold Organization name:uniq
rails g scaffold Role name
rails g scaffold Membership user:references organization:references role:refences
user.rb
class User < ApplicationRecord
has_many :memberships
has_many :roles, through: :memberships
has_many :organizations, through: :memberships
end
membership.rb
class Membership < ApplicationRecord
belongs_to :role
belongs_to :organization
belongs_to :user
end
organization.rb
class Organization < ApplicationRecord
has_many :memberships
has_many :users, through: :memberships
end
role.rb
class Role < ApplicationRecord
has_many :memberships
has_many :users, through: :memberships
end
seeds.rb
admin = Role.create(name: 'Admin')
user = Role.create(name: 'User')
abc = Organization.create(name: 'Abc Inc.')
bob = User.create(first_name: 'Bob')
alice = User.create(first_name: 'Alice')
Membership.create(role: user, company: abc, role: user)
Membership.create(role: admin, company: abc, role: admin)
管理员应该能够管理其所管理的公司的所有用户和成员身份。用户只能读取该公司的所有用户和会员资格。
这是我的cancancan配置:
ability.rb
class Ability
include CanCan::Ability
def initialize(user)
user ||= User.new
user_role = Role.find_by_name('User')
admin_role = Role.find_by_name('Admin')
organizations_with_user_role = Organization.includes(:memberships).
where(memberships: {user_id: user.id, role_id: user_role.id})
organizations_with_admin_role = Organization.includes(:memberships).
where(memberships: {user_id: user.id, role_id: admin_role.id})
can :read, Organization, organizations_with_user_role
can :manage, Organization, organizations_with_admin_role
end
end
然后我尝试在视图中运行此代码:
<% if can? :read, organization %><%= link_to 'Show', organization %><% end %>
这将导致错误页面显示:
可以吗?不能吗?调用不能与原始sql“可以”定义一起使用。无法为:read#
确定检查代码我想我从一个完全错误的角度解决了这个问题。我该如何设置ability.rb
来解决此问题?
答案 0 :(得分:2)
我将在此处使用简单的条件散列:
can :read, Organization, memberships: { user_id: user.id, role: { name: 'User' } }
can :manage, Organization, memberships: { user_id: user.id, role: { name: 'Admin' } }
这应该足够了,您的好处是,使用这种语法,您还可以调用Organization.accessible_by(ability,:read)并检索用户可以读取的所有组织。
答案 1 :(得分:1)
几乎所有您可以传递给Active条件散列的内容 记录将在这里工作。唯一的例外是使用模型ID。 您不能直接传递模型对象,必须传递 ID。
[09:06:56] Error - typescript - src\...\TruckDeliverySchedule.tsx(154,27): error TS2461: Type 'IterableIterator<any>' is not an array type.
因此,请尝试以下操作:
can :manage, Project, group: { id: user.group_ids }
另外,为什么要使用can :read, Organization, id: organizations_with_user_role.pluck(:id)
而不是includes
?您的查询可以简化为(不需要joins
):
user_role = Role.find_by_name('User')