【发布时间】:2012-04-11 23:57:50
【问题描述】:
维护具有自定义基于角色的授权系统的现有 Rails 2.3.x 应用程序。
代码是这样的:
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, 10002, VIP, 5003, regular, 1004, 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
如果不求助于编写原始 SQL 查询,我无法理解如何在 Rails 中执行此操作。
有什么建议吗?
更新: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 替换对 scoped() 的调用(update: DOES NOT)解决了计数问题。
因此,为了正确/简洁,我将 Chris 的提议与一些编辑结合在一起。谢谢!
另一个更新。
其实 :group 和 : 没有通过的问题也在 named_scoped 实现中。
果然这是一张陈旧的票,没有修复过 Rails 源代码树(至少不在 2.3.x 分支中)。
https://rails.lighthouseapp.com/projects/8994/tickets/1349-named-scope-with-group-by-bug
太好了……
【问题讨论】:
标签: ruby-on-rails join has-and-belongs-to-many