Поддержка существующего приложения 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, 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-запросов.
Есть предложения?
Обновление: 29 марта 2012 г.
Это было мое решение, чтобы в основном определить кучу таких методов (хорошо используя некоторое динамическое программирование вместе с 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
Однако я обнаружил, что существует проблема со старыми рельсами 2.3.x. Например, вызов size () или count () для Member.vips_exclusively приведет к неверным результатам. Вызов length () даст правильный результат, но рекомендуется использовать size () везде, где это возможно.
После просмотра кода Rails выглядит, что такие параметры, как :group
и :having
, не передаются в count () при установке в scoped (). Замена вызовов функции scoped () на named_scopes ( обновление: НЕ ) решает проблему подсчета.
Поэтому я включил предложение Криса вместе с некоторыми правками для правильности / краткости. Спасибо!
Еще одно обновление.
На самом деле проблема: group и: не пройдя также находится в реализации named_scoped.
И, конечно же, вот устаревший тикет, без каких-либо исправлений, когда-либо вносимых в дерево исходных текстов Rails (по крайней мере, в ветке 2.3.x).
https://rails.lighthouseapp.com/projects/8994/tickets/1349-named-scope-with-group-by-bug
Отлично ...