【发布时间】:2015-11-11 16:40:25
【问题描述】:
我的 Rails 应用程序有许多形成层次结构的模型。例如:零售商 > 部门 > 产品类别 > 产品 > 评论。
业务需求是高权限用户可以与新的或现有的“普通”用户“共享”层次结构中的任何单个元素。在没有与他们共享对象的情况下,普通用户无权查看(或执行其他任何操作)层次结构中任何级别的任何对象。
共享过程包括选择共享是否授予对目标对象的只读、读取更新或完整 CRUD 权限。
共享任何对象会授予该对象和层次结构中所有较低级别对象的 R/O、R/W 或 CRUD 权限,以及授予对象的所有直接祖先的 R/O 权限。对象集合有机地增长,因此权限系统仅通过记录 user_id、共享的 object_id 和共享的性质(R/O、CRUD 等)来工作。由于此层次结构中的对象数量一直在增长,因此在数据库中为每个用户/对象组合创建明确的权限记录是不切实际的。
相反,在用户请求周期开始时,ApplicationController 收集所有权限记录(用户 X 对部门 #5 具有 CRUD 权限)并将它们保存在内存中的哈希中。 Permissions 模型知道在将任何对象传递给它时如何评估散列 - Permission.allow?(:show, Department#5) 将根据用户权限散列的内容返回 true 或 false。
我们以部门模型为例:
# app/models/department.rb
class Department < ActiveRecord::Base
after_initialize :check_permission
private
def check_permission
# some code that returns true or false
end
end
当check_permission方法返回true时,我希望Department.first正常带回数据库中的第一条记录,但是,如果check_permission返回false,我想返回nil。
现在,我有一个解决方案,默认范围触发权限检查,但这会导致查询数量增加 2 倍,并且对于具有大量对象的类,内存问题和时间/性能问题肯定会出现地平线。
我的目标是使用after_initialize 回调来预授权对象。
然而,after_initialize 似乎无法阻止返回原始对象。它确实允许我重置对象属性的值,但不能放弃它。
有人知道如何实现吗?
编辑:
非常感谢到目前为止提供的所有答案和 cmets;希望这个问题的扩展版本可以澄清问题。
【问题讨论】:
-
after_initialize没有按照您的预期去做。它在那里执行一些副作用。它不会给你任何回报。您的需求/要求到底是什么? -
我认为您不应该尝试这样做,我认为没有权限系统可以在该级别进行拦截,因为这不是您应该执行的级别。相反,您可能应该在 User 和 Department 之间建立关系。
check_permission到底在检查什么? -
用户和部门之间没有直接关系。有问题的 Rails 应用程序具有对象层次结构(例如租户、部门、产品类别、产品等)。可以在任何级别向特定对象授予权限;所有子级都继承完全权限,所有上级继承只读权限。 “check_permission”方法调用一个 ActiveModel 模型来找出用户允许的特定对象(部门 #1 等)。
标签: ruby-on-rails activerecord callback rails-activerecord