In episode 189 of Railscasts, there is a named scope in the User model which is as follows:
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 role开发者_如何转开发s
ROLES.reject { |r| ((roles_mask || 0) & 2**ROLES.index(r)).zero? }
end
def role_symbols
roles.map(&:to_sym)
end
How would one get it to work on Mongoid as I tried the a number of options and could not get it to work?
That episode of Railscasts was really designed for databases that don't support arrays as native types (which Mongoid does). Then you could just create a scope which uses one of the array query criteria.
For example:
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
This example would allow you to pass in either a single role User.with_role("admin")
or an array of roles User.with_role("moderator", "author")
, with the latter returning users who are either moderators or authors.
You can use the native map reduce mongoDB machanism which is exposed through mongoid using for_js method 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
This will give scopes in the form of:
User.admins
User.moderators
User.authors
精彩评论