如何验证数组所有值存在于哈希指定键的集合中及检查用户是否具备全部指定权限范围
解决用户权限范围的全量验证问题
你的思路方向是对的,但之前的代码确实存在重复计数的bug——同一个权限在多个角色里出现会被多次统计,导致误判。我们可以利用Ruby的集合(Set)特性来简洁高效地解决这个问题,核心思路是先合并用户所有角色的权限并去重,再验证指定权限是否全部属于这个集合。
正确的简洁实现
首先,我们可以封装一个方法来完成验证逻辑:
scopes_for_roles = { artist: ['draw', 'sing'], teacher: ['read', 'write'], athlete: ['draw', 'read', 'dance'] } def has_all_required_scopes?(user_roles, required_scopes, scopes_map) # 合并用户所有角色的权限,转成Set去重(提高查询效率) user_available_scopes = user_roles.flat_map { |role| scopes_map[role] || [] }.to_set # 检查所有指定权限是否都是用户权限集合的子集 required_scopes.to_set.subset?(user_available_scopes) end
测试示例
用你给出的场景验证:
- 验证
['read', 'write']:has_all_required_scopes?([:athlete, :teacher], ['read', 'write'], scopes_for_roles) # 返回 true - 验证
['sing', 'read', 'write', 'dance']:has_all_required_scopes?([:athlete, :teacher], ['sing', 'read', 'write', 'dance'], scopes_for_roles) # 返回 false(缺少sing权限) - 验证你提到的bug场景
['read', 'sing']:has_all_required_scopes?([:athlete, :teacher], ['read', 'sing'], scopes_for_roles) # 返回 false(正确,用户没有sing权限)
为什么之前的代码会出错?
你之前的product.select.size逻辑,会把同一个权限在多个角色中出现的情况重复计数。比如read在athlete和teacher角色中都存在,会被统计两次,当你验证['read', 'sing']时,筛选后的组合数量是2,刚好等于权限列表长度2,导致错误返回true,但实际上用户并没有sing权限。
替代简化写法(不需要Set)
如果你的权限数量不多,也可以不用Set,直接用数组的all?方法检查每个权限是否存在:
def has_all_required_scopes?(user_roles, required_scopes, scopes_map) user_available_scopes = user_roles.flat_map { |role| scopes_map[role] || [] } required_scopes.all? { |scope| user_available_scopes.include?(scope) } end
这种写法更直观,但查询效率不如Set(数组include?是O(n),Set是O(1)),适合小规模权限场景。
内容的提问来源于stack exchange,提问作者Liondancer
相关产品推荐
相关产品推荐

