维护具有基于角色的自定义授权系统的现有Rails 2.3.x应用程序。rails habtm:返回关联的记录但独占匹配
代码必须是这样的:
class Role << AR:Base
# has an int attribute called "level" with higher values indicating more powerful role
habtm: members
end
class Member << AR:Base
habtm: roles
end
角色表有类似
(id, name, level)
1, admin, 1000
2, VIP, 500
3, regular, 100
4, some_other_role, 50
我有以下成员说明角色
的member1(角色:admin
,VIP
,regular
)
member2(角色:VIP
,regular
)
member3(角色:regular
)
我需要有时是拉起人员根据其分配的最高角色:
Role.admins_exclusively # should return member1
Role.vips_exclusively # should return just member2
Role.regulars_exclusively # should be just member3
无法将我的头围绕如何在Rails中执行此操作,而无需诉诸写入原始SQL查询。
有什么建议吗?
更新:2012年3月29日
这是我的解决方案基本上确定了一堆为每个角色这样的(()使用以及一些动态规划与define_method一起)的方法。
class Member < AR:Base
define_method :vips_exclusively do
scoped :joins => :roles,
:group => 'members.id',
:having => ["max(roles.level) = ?", Role.find_by_name('vip').level]
end
end
但是,我发现旧的rails 2.3.x有一个问题。例如,在Member.vips_exclusively上调用size()或count()会产生不正确的总数。调用length()会产生正确的结果,但建议尽可能使用size()。
查看Rails代码后,看起来像:group
和:having
之类的选项在scoped()中设置时不会传递给count()。用named_scopes替换调用范围()(更新:不是)解决了计数问题。
因此,我将克里斯的建议与一些编辑结合起来,以保证正确性和简洁性。谢谢!
另一个更新。
其实问题:group和:没有被传递也在named_scoped实现中。
果然,这里有一张陈旧的票据,没有任何修复,使它成为Rails源代码树(至少不在2.3.x分支中)。
https://rails.lighthouseapp.com/projects/8994/tickets/1349-named-scope-with-group-by-bug
太棒了......