lib/groupify/adapter/mongoid.rb in groupify-0.5.1 vs lib/groupify/adapter/mongoid.rb in groupify-0.6.0.rc1
- old
+ new
@@ -53,36 +53,44 @@
included do
@default_member_class = nil
@member_klasses ||= Set.new
end
- def members
- self.class.default_member_class.any_in(:group_ids => [self.id])
- end
+ # def members
+ # self.class.default_member_class.any_in(:group_ids => [self.id])
+ # end
def member_classes
self.class.member_classes
end
- def add(*members)
- members.flatten.each do |member|
+ def add(*args)
+ opts = args.extract_options!
+ membership_type = opts[:as]
+ members = args.flatten
+ return unless members.present?
+
+ members.each do |member|
member.groups << self
+ membership = member.group_memberships.find_or_initialize_by(as: membership_type)
+ membership.groups << self
+ membership.save!
end
end
# Merge a source group into this group.
def merge!(source)
self.class.merge!(source, self)
end
module ClassMethods
def with_member(member)
- criteria.for_ids(member.group_ids)
+ member.groups
end
def default_member_class
- @default_member_class ||= register(User)
+ @default_member_class ||= User rescue false
end
def default_member_class=(klass)
@default_member_class = klass
end
@@ -94,15 +102,10 @@
# Define which classes are members of this group
def has_members(name)
klass = name.to_s.classify.constantize
register(klass)
-
- # Define specific members accessor, i.e. group.users
- define_method name.to_s.pluralize.underscore do
- klass.any_in(:group_ids => [self.id])
- end
end
# Merge two groups. The members of the source become members of the destination, and the source is destroyed.
def merge!(source_group, destination_group)
# Ensure that all the members of the source can be members of the destination
@@ -122,14 +125,88 @@
protected
def register(member_klass)
(@member_klasses ||= Set.new) << member_klass
+ associate_member_class(member_klass)
member_klass
end
+
+ module MemberAssociationExtensions
+ def as(membership_type)
+ return self unless membership_type
+ where(:group_memberships.elem_match => { as: membership_type.to_s, group_ids: [base.id] })
+ end
+
+ def destroy(*args)
+ delete(*args)
+ end
+
+ def delete(*args)
+ opts = args.extract_options!
+ members = args
+
+ if opts[:as]
+ members.each do |member|
+ member.group_memberships.as(opts[:as]).first.groups.delete(base)
+ end
+ else
+ members.each do |member|
+ member.group_memberships.in(groups: base).each do |membership|
+ membership.groups.delete(base)
+ end
+ end
+
+ super(*members)
+ end
+ end
+ end
+
+ def associate_member_class(member_klass)
+ association_name = member_klass.name.to_s.pluralize.underscore.to_sym
+
+ has_many association_name, class_name: member_klass.to_s, dependent: :nullify, foreign_key: 'group_ids', extend: MemberAssociationExtensions
+
+ if member_klass == default_member_class
+ has_many :members, class_name: member_klass.to_s, dependent: :nullify, foreign_key: 'group_ids', extend: MemberAssociationExtensions
+ end
+ end
end
end
+
+ module MemberScopedAs
+ extend ActiveSupport::Concern
+
+ module ClassMethods
+ def as(membership_type)
+ group_ids = criteria.selector["group_ids"]
+ named_groups = criteria.selector["named_groups"]
+ criteria = self.criteria
+
+ # If filtering by groups or named groups, merge into the group membership criteria
+ if group_ids || named_groups
+ elem_match = {as: membership_type}
+
+ if group_ids
+ elem_match.merge!(group_ids: group_ids)
+ end
+
+ if named_groups
+ elem_match.merge!(named_groups: named_groups)
+ end
+
+ criteria = where(:group_memberships.elem_match => elem_match)
+ criteria.selector.delete("group_ids")
+ criteria.selector.delete("named_groups")
+ else
+ criteria = where(:"group_memberships.as" => membership_type)
+ end
+
+ criteria
+ end
+ end
+ end
# Usage:
# class User
# include Mongoid::Document
#
@@ -139,56 +216,208 @@
#
# user.groups << group
#
module GroupMember
extend ActiveSupport::Concern
+ include MemberScopedAs
included do
- has_and_belongs_to_many :groups, :autosave => true, :inverse_of => nil, :class_name => @group_class_name
+ has_and_belongs_to_many :groups, autosave: true, dependent: :nullify, inverse_of: nil, class_name: @group_class_name do
+ def as(membership_type)
+ return self unless membership_type
+ group_ids = base.group_memberships.as(membership_type).first.group_ids
+
+ if group_ids.present?
+ self.and(:id.in => group_ids)
+ else
+ self.and(:id => nil)
+ end
+ end
+
+ def destroy(*args)
+ delete(*args)
+ end
+
+ def delete(*args)
+ opts = args.extract_options!
+ groups = args.flatten
+
+
+ if opts[:as]
+ base.group_memberships.as(opts[:as]).each do |membership|
+ membership.groups.delete(*groups)
+ end
+ else
+ super(*groups)
+ end
+ end
+ end
+
+ class GroupMembership
+ include ::Mongoid::Document
+
+ embedded_in :member, polymorphic: true
+
+ field :named_groups, type: Array, default: -> { [] }
+
+ after_initialize do
+ named_groups.extend NamedGroupCollection
+ end
+
+ field :as, as: :membership_type, type: String
+ end
+
+ GroupMembership.send :has_and_belongs_to_many, :groups, class_name: @group_class_name, inverse_of: nil
+
+ embeds_many :group_memberships, class_name: GroupMembership.to_s, as: :member do
+ def as(membership_type)
+ where(membership_type: membership_type.to_s)
+ end
+ end
end
- def in_group?(group)
- self.groups.include?(group)
+ def in_group?(group, opts={})
+ groups.as(opts[:as]).include?(group)
end
- def in_any_group?(*groups)
+ def in_any_group?(*args)
+ opts = args.extract_options!
+ groups = args
+
groups.flatten.each do |group|
- return true if in_group?(group)
+ return true if in_group?(group, opts)
end
return false
end
-
- def in_all_groups?(*groups)
- Set.new(groups.flatten) == Set.new(self.named_groups)
+
+ def in_all_groups?(*args)
+ opts = args.extract_options!
+ groups = args
+
+ groups.flatten.to_set.subset? self.groups.as(opts[:as]).to_set
end
-
- def shares_any_group?(other)
- in_any_group?(other.groups)
+
+ def in_only_groups?(*args)
+ opts = args.extract_options!
+ groups = args.flatten
+
+ groups.to_set == self.groups.as(opts[:as]).to_set
end
+
+ def shares_any_group?(other, opts={})
+ in_any_group?(other.groups.to_a, opts)
+ end
module ClassMethods
def group_class_name; @group_class_name ||= 'Group'; end
def group_class_name=(klass); @group_class_name = klass; end
def in_group(group)
- group.present? ? where(:group_ids.in => [group.id]) : none
+ group.present? ? self.in(group_ids: group.id) : none
end
def in_any_group(*groups)
- groups.present? ? where(:group_ids.in => groups.flatten.map(&:id)) : none
+ groups.present? ? self.in(group_ids: groups.flatten.map(&:id)) : none
end
-
+
def in_all_groups(*groups)
+ groups.present? ? where(:group_ids.all => groups.flatten.map(&:id)) : none
+ end
+
+ def in_only_groups(*groups)
groups.present? ? where(:group_ids => groups.flatten.map(&:id)) : none
end
def shares_any_group(other)
- in_any_group(other.groups)
+ in_any_group(other.groups.to_a)
end
end
end
+
+ module NamedGroupCollection
+ # Criteria to filter by membership type
+ def as(membership_type)
+ return self unless membership_type
+
+ membership = @member.group_memberships.as(membership_type).first
+ if membership
+ membership.named_groups
+ else
+ self.class.new
+ end
+ end
+
+ def <<(named_group, opts={})
+ named_group = named_group.to_sym
+ super(named_group)
+ uniq!
+
+ if @member && opts[:as]
+ membership = @member.group_memberships.find_or_initialize_by(as: opts[:as])
+ membership.named_groups << named_group
+ membership.save!
+ end
+
+ self
+ end
+
+ def merge(*args)
+ opts = args.extract_options!
+ named_groups = args.flatten
+
+ named_groups.each do |named_group|
+ add(named_group, opts)
+ end
+ end
+
+ def delete(*args)
+ opts = args.extract_options!
+ named_groups = args.flatten
+
+ if @member
+ if opts[:as]
+ membership = @member.group_memberships.as(opts[:as]).first
+ if membership
+ if ::Mongoid::VERSION > "4"
+ membership.pull_all(named_groups: named_groups)
+ else
+ membership.pull_all(:named_groups, named_groups)
+ end
+ end
+
+ return
+ else
+ memberships = @member.group_memberships.where(:named_groups.in => named_groups)
+ memberships.each do |membership|
+ if ::Mongoid::VERSION > "4"
+ membership.pull_all(named_groups: named_groups)
+ else
+ membership.pull_all(:named_groups, named_groups)
+ end
+ end
+ end
+ end
+
+ named_groups.each do |named_group|
+ super(named_group)
+ end
+ end
+
+ def self.extended(base)
+ base.class_eval do
+ attr_accessor :member
+
+ alias_method :delete_all, :clear
+ alias_method :destroy_all, :clear
+ alias_method :push, :<<
+ alias_method :add, :<<
+ alias_method :concat, :merge
+ alias_method :destroy, :delete
+ end
+ end
+ end
# Usage:
# class User
# include Mongoid::Document
#
@@ -198,54 +427,80 @@
#
# user.named_groups << :admin
#
module NamedGroupMember
extend ActiveSupport::Concern
+ include MemberScopedAs
included do
- field :named_groups, :type => Array, :default => []
-
- before_save :uniq_named_groups
- protected
- def uniq_named_groups
- named_groups.uniq!
+ field :named_groups, type: Array, default: -> { [] }
+
+ after_initialize do
+ named_groups.extend NamedGroupCollection
+ named_groups.member = self
end
end
- def in_named_group?(group)
- named_groups.include?(group)
+ def in_named_group?(named_group, opts={})
+ named_groups.as(opts[:as]).include?(named_group)
end
- def in_any_named_group?(*groups)
- groups.flatten.each do |group|
- return true if in_named_group?(group)
+ def in_any_named_group?(*args)
+ opts = args.extract_options!
+ group_names = args.flatten
+
+ group_names.each do |named_group|
+ return true if in_named_group?(named_group)
end
+
return false
end
- def in_all_named_groups?(*groups)
- Set.new(groups.flatten) == Set.new(self.named_groups)
+ def in_all_named_groups?(*args)
+ opts = args.extract_options!
+ named_groups = args.flatten.to_set
+
+ named_groups.subset? self.named_groups.as(opts[:as]).to_set
end
+
+ def in_only_named_groups?(*args)
+ opts = args.extract_options!
+ named_groups = args.flatten.to_set
+ named_groups == self.named_groups.as(opts[:as]).to_set
+ end
- def shares_any_named_group?(other)
- in_any_named_group?(other.named_groups)
+ def shares_any_named_group?(other, opts={})
+ in_any_named_group?(other.named_groups, opts)
end
module ClassMethods
- def in_named_group(named_group)
- named_group.present? ? where(:named_groups.in => [named_group]) : none
+ def in_named_group(named_group, opts={})
+ in_any_named_group(named_group, opts)
end
def in_any_named_group(*named_groups)
- named_groups.present? ? where(:named_groups.in => named_groups.flatten) : none
+ named_groups.flatten!
+ return none unless named_groups.present?
+
+ self.in(named_groups: named_groups.flatten)
end
-
+
def in_all_named_groups(*named_groups)
- named_groups.present? ? where(:named_groups => named_groups.flatten) : none
+ named_groups.flatten!
+ return none unless named_groups.present?
+
+ where(:named_groups.all => named_groups.flatten)
end
- def shares_any_named_group(other)
- in_any_named_group(other.named_groups)
+ def in_only_named_groups(*named_groups)
+ named_groups.flatten!
+ return none unless named_groups.present?
+
+ where(named_groups: named_groups.flatten)
+ end
+
+ def shares_any_named_group(other, opts={})
+ in_any_named_group(other.named_groups, opts)
end
end
end
end
end