拥有会员资格的用户可以读取所有数据
User with a membership can read all data
设置
我正在使用 Rails 5.2 和 cancancan gem。
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)
任务
管理员应该能够管理公司的所有用户和会员资格 he/she 是管理员。一个用户只能读取该公司的所有用户和会员。
这是我对 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 %>
这会导致错误页面显示:
可以吗?不能? call 不能与原始 sql 'can' 定义一起使用。无法确定校验码:read #
我想我是从一个完全错误的角度来解决问题的。我必须如何设置 ability.rb
才能解决这个问题?
Almost anything that you can pass to a hash of conditions in Active
Record will work here. The only exception is working with model ids.
You can't pass in the model objects directly, you must pass in the
ids.
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')
):
organizations_with_user_role = Organization.joins(memberships: :role).
where(memberships: {user_id: user.id}).where(roles: {name: 'User'})
我会在这里使用一个简单的条件散列:
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) 并检索用户可以阅读的所有组织。
设置
我正在使用 Rails 5.2 和 cancancan gem。
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)
任务
管理员应该能够管理公司的所有用户和会员资格 he/she 是管理员。一个用户只能读取该公司的所有用户和会员。
这是我对 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 %>
这会导致错误页面显示:
可以吗?不能? call 不能与原始 sql 'can' 定义一起使用。无法确定校验码:read #
我想我是从一个完全错误的角度来解决问题的。我必须如何设置 ability.rb
才能解决这个问题?
Almost anything that you can pass to a hash of conditions in Active Record will work here. The only exception is working with model ids. You can't pass in the model objects directly, you must pass in the ids.
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')
):
organizations_with_user_role = Organization.joins(memberships: :role).
where(memberships: {user_id: user.id}).where(roles: {name: 'User'})
我会在这里使用一个简单的条件散列:
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) 并检索用户可以阅读的所有组织。