diff --git a/app/models/profile.rb b/app/models/profile.rb index 37deb3d..3537f86 100644 --- a/app/models/profile.rb +++ b/app/models/profile.rb @@ -84,7 +84,8 @@ class Profile < ActiveRecord::Base def members scopes = plugins.dispatch_scopes(:organization_members, self) scopes << Person.members_of(self) - scopes.size == 1 ? scopes.first : Person.or_scope(scopes) + return scopes.first if scopes.size == 1 + ScopeTool.union *scopes end def members_count diff --git a/lib/scope_tool.rb b/lib/scope_tool.rb new file mode 100644 index 0000000..7128af9 --- /dev/null +++ b/lib/scope_tool.rb @@ -0,0 +1,13 @@ +module ScopeTool + + def union(*scopes) + model = scopes.first.class_name.constantize + scopes = scopes.map &:to_sql + model.from "(\n#{scopes.join("\nUNION\n")}\n) as #{model.table_name}" + end + + class << self + include ScopeTool + end + +end diff --git a/test/unit/scope_tool.rb b/test/unit/scope_tool.rb new file mode 100644 index 0000000..8a91c54 --- /dev/null +++ b/test/unit/scope_tool.rb @@ -0,0 +1,31 @@ +require File.dirname(__FILE__) + '/../test_helper' + +class ScopeToolTest < ActiveSupport::TestCase + include ScopeTool + + should 'unite scopes' do + cmm = fast_create Community + ent = fast_create Enterprise + orgs = union(Profile.communities, Profile.enterprises) + assert orgs.include? cmm + assert orgs.include? ent + end + + should 'filter united scopes' do + cmm1 = fast_create Community, :visible => true + cmm2 = fast_create Community, :visible => false + ent1 = fast_create Enterprise, :visible => true + ent2 = fast_create Enterprise, :visible => false + orgs = union(Profile.communities, Profile.enterprises) + assert orgs.include? cmm1 + assert orgs.include? cmm2 + assert orgs.include? ent1 + assert orgs.include? ent2 + orgs = orgs.visible + assert orgs.include? cmm1 + assert !orgs.include?(cmm2) + assert orgs.include? ent1 + assert !orgs.include?(ent2) + end + +end diff --git a/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb b/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb index 817f52b..80fc0e6 100644 --- a/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb +++ b/vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb @@ -19,14 +19,6 @@ module Rails3Finder named_scope :readonly, lambda {|readonly| {:readonly => readonly }} named_scope :lock, lambda {|lock| {:lock => lock }} - def self.select(value = Proc.new) - if block_given? - all.select {|*block_args| value.call(*block_args) } - else - self.scoped(:select => Array.wrap(value).join(',')) - end - end - __where_fn = lambda do |*where| if where.is_a?(Array) and where.size == 1 {:conditions => where.first} @@ -37,33 +29,66 @@ module Rails3Finder named_scope :where, __where_fn - # Use carefully this method! It might get lost with different classes - # scopes or different types of joins. - def self.or_scope(*scopes) - where = [] - joins = [] - includes = [] + class << self - # for some reason, flatten is actually executing the scope - scopes = scopes[0] if scopes.size == 1 - scopes.each do |s| - s = s.proxy_options - begin - where << merge_conditions(s[:conditions]) - rescue NoMethodError - # I am ActiveRecord::Base. Only my subclasses define merge_conditions: - where << subclasses.first.merge_conditions(s[:conditions]) + def select(value = Proc.new) + if block_given? + all.select {|*block_args| value.call(*block_args) } + else + self.scoped(:select => Array.wrap(value).join(',')) end - #where << merge_conditions(s[:conditions]) - joins << s[:joins] unless s[:joins].nil? - includes << s[:include] unless s[:include].nil? end - scoped = self - scoped = scoped.select("DISTINCT #{self.table_name}.*") - scoped = scoped.includes(includes.uniq.flatten) unless includes.blank? - scoped = scoped.joins(joins.uniq.flatten) unless joins.blank? - scoped.where(where.join(" OR ")) + + def to_sql + join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), nil), nil) + scope = scope(:find) || {} + options = current_scoped_methods || {} + sql = "SELECT #{(scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} " + sql << "FROM #{(scope && scope[:from]) || quoted_table_name} " + sql << join_dependency.join_associations.collect{|join| join.association_join }.join + + add_joins!(sql, options[:joins], scope) + add_conditions!(sql, options[:conditions], scope) + add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit]) + + add_group!(sql, options[:group], options[:having], scope) + add_order!(sql, options[:order], scope) + add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections) + add_lock!(sql, options, scope) + + return sanitize_sql(sql) + end + + # Use carefully this method! It might get lost with different classes + # scopes or different types of joins. + def or_scope(*scopes) + where = [] + joins = [] + includes = [] + + # for some reason, flatten is actually executing the scope + scopes = scopes[0] if scopes.size == 1 + scopes.each do |s| + s = s.proxy_options + begin + where << merge_conditions(s[:conditions]) + rescue NoMethodError + # I am ActiveRecord::Base. Only my subclasses define merge_conditions: + where << subclasses.first.merge_conditions(s[:conditions]) + end + #where << merge_conditions(s[:conditions]) + joins << s[:joins] unless s[:joins].nil? + includes << s[:include] unless s[:include].nil? + end + scoped = self + scoped = scoped.select("DISTINCT #{self.table_name}.*") + scoped = scoped.includes(includes.uniq.flatten) unless includes.blank? + scoped = scoped.joins(joins.uniq.flatten) unless joins.blank? + scoped.where(where.join(" OR ")) + end + end + end end end -- libgit2 0.21.2