在Railscasts的第189集中,用户模型中有一个命名范围,如下所示:
field :roles_mask, :type => Integer
ROLES = %w[admin moderator author]
named_scope :with_role, lambda { |role| {:conditions => "roles_mask & #{2**ROLES.index(role.to_s)} > 0"} }
# roles related
def roles=(roles)
self.roles_mask = (roles & ROLES).map { |r| 2**ROLES.index(r) }.sum
end
def roles
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end
def role_symbols
roles.map(&:to_sym)
end
当我尝试了很多选项但都无法让它工作时,如何让它在Mongoid上工作?
Railscasts的那一集实际上是为那些不支持数组作为本机类型的数据库设计的(Mongoid就是这样做的)。然后,您可以创建一个使用数组查询条件之一的作用域。
例如:
class User
include Mongoid::Document
field :email
field :roles, :type => Array
ROLES = %w[admin moderator author]
class << self
def with_role(*args)
any_in(:roles => args)
end
end
end
此示例允许您传入单个角色User.with_role("admin")
或一组角色User.with_role("moderator", "author")
,后者返回的用户要么是管理员,要么是作者。
您可以使用原生map reduce mongoDB机制,该机制通过使用for_js方法的mongoid公开http://www.rubydoc.info/github/mongoid/mongoid/Mongoid/Criteria:for_js
ROLES.each_with_index do |role, role_index|
scope "#{role.to_s.pluralize}", -> { self.for_js("(this.roles_mask & (1 << role_val)) > 0", role_val: role_index) }
end
这将提供以下形式的范围:
User.admins
User.moderators
User.authors