Commit 0b31911bd64211099153a1dd30feede66d6d2a91

Authored by Aurélio A. Heckert
Committed by Daniel
1 parent b1bcaade

Make scope unions

closes ActionItem2830
app/models/profile.rb
... ... @@ -84,7 +84,8 @@ class Profile < ActiveRecord::Base
84 84 def members
85 85 scopes = plugins.dispatch_scopes(:organization_members, self)
86 86 scopes << Person.members_of(self)
87   - scopes.size == 1 ? scopes.first : Person.or_scope(scopes)
  87 + return scopes.first if scopes.size == 1
  88 + ScopeTool.union *scopes
88 89 end
89 90  
90 91 def members_count
... ...
lib/scope_tool.rb 0 → 100644
... ... @@ -0,0 +1,13 @@
  1 +module ScopeTool
  2 +
  3 + def union(*scopes)
  4 + model = scopes.first.class_name.constantize
  5 + scopes = scopes.map &:to_sql
  6 + model.from "(\n#{scopes.join("\nUNION\n")}\n) as #{model.table_name}"
  7 + end
  8 +
  9 + class << self
  10 + include ScopeTool
  11 + end
  12 +
  13 +end
... ...
test/unit/scope_tool.rb 0 → 100644
... ... @@ -0,0 +1,31 @@
  1 +require File.dirname(__FILE__) + '/../test_helper'
  2 +
  3 +class ScopeToolTest < ActiveSupport::TestCase
  4 + include ScopeTool
  5 +
  6 + should 'unite scopes' do
  7 + cmm = fast_create Community
  8 + ent = fast_create Enterprise
  9 + orgs = union(Profile.communities, Profile.enterprises)
  10 + assert orgs.include? cmm
  11 + assert orgs.include? ent
  12 + end
  13 +
  14 + should 'filter united scopes' do
  15 + cmm1 = fast_create Community, :visible => true
  16 + cmm2 = fast_create Community, :visible => false
  17 + ent1 = fast_create Enterprise, :visible => true
  18 + ent2 = fast_create Enterprise, :visible => false
  19 + orgs = union(Profile.communities, Profile.enterprises)
  20 + assert orgs.include? cmm1
  21 + assert orgs.include? cmm2
  22 + assert orgs.include? ent1
  23 + assert orgs.include? ent2
  24 + orgs = orgs.visible
  25 + assert orgs.include? cmm1
  26 + assert !orgs.include?(cmm2)
  27 + assert orgs.include? ent1
  28 + assert !orgs.include?(ent2)
  29 + end
  30 +
  31 +end
... ...
vendor/plugins/monkey_patches/methods_from_fake_arel/init.rb
... ... @@ -19,14 +19,6 @@ module Rails3Finder
19 19 named_scope :readonly, lambda {|readonly| {:readonly => readonly }}
20 20 named_scope :lock, lambda {|lock| {:lock => lock }}
21 21  
22   - def self.select(value = Proc.new)
23   - if block_given?
24   - all.select {|*block_args| value.call(*block_args) }
25   - else
26   - self.scoped(:select => Array.wrap(value).join(','))
27   - end
28   - end
29   -
30 22 __where_fn = lambda do |*where|
31 23 if where.is_a?(Array) and where.size == 1
32 24 {:conditions => where.first}
... ... @@ -37,33 +29,66 @@ module Rails3Finder
37 29  
38 30 named_scope :where, __where_fn
39 31  
40   - # Use carefully this method! It might get lost with different classes
41   - # scopes or different types of joins.
42   - def self.or_scope(*scopes)
43   - where = []
44   - joins = []
45   - includes = []
  32 + class << self
46 33  
47   - # for some reason, flatten is actually executing the scope
48   - scopes = scopes[0] if scopes.size == 1
49   - scopes.each do |s|
50   - s = s.proxy_options
51   - begin
52   - where << merge_conditions(s[:conditions])
53   - rescue NoMethodError
54   - # I am ActiveRecord::Base. Only my subclasses define merge_conditions:
55   - where << subclasses.first.merge_conditions(s[:conditions])
  34 + def select(value = Proc.new)
  35 + if block_given?
  36 + all.select {|*block_args| value.call(*block_args) }
  37 + else
  38 + self.scoped(:select => Array.wrap(value).join(','))
56 39 end
57   - #where << merge_conditions(s[:conditions])
58   - joins << s[:joins] unless s[:joins].nil?
59   - includes << s[:include] unless s[:include].nil?
60 40 end
61   - scoped = self
62   - scoped = scoped.select("DISTINCT #{self.table_name}.*")
63   - scoped = scoped.includes(includes.uniq.flatten) unless includes.blank?
64   - scoped = scoped.joins(joins.uniq.flatten) unless joins.blank?
65   - scoped.where(where.join(" OR "))
  41 +
  42 + def to_sql
  43 + join_dependency = JoinDependency.new(self, merge_includes(scope(:find, :include), nil), nil)
  44 + scope = scope(:find) || {}
  45 + options = current_scoped_methods || {}
  46 + sql = "SELECT #{(scope && scope[:select]) || default_select(options[:joins] || (scope && scope[:joins]))} "
  47 + sql << "FROM #{(scope && scope[:from]) || quoted_table_name} "
  48 + sql << join_dependency.join_associations.collect{|join| join.association_join }.join
  49 +
  50 + add_joins!(sql, options[:joins], scope)
  51 + add_conditions!(sql, options[:conditions], scope)
  52 + add_limited_ids_condition!(sql, options, join_dependency) if !using_limitable_reflections?(join_dependency.reflections) && ((scope && scope[:limit]) || options[:limit])
  53 +
  54 + add_group!(sql, options[:group], options[:having], scope)
  55 + add_order!(sql, options[:order], scope)
  56 + add_limit!(sql, options, scope) if using_limitable_reflections?(join_dependency.reflections)
  57 + add_lock!(sql, options, scope)
  58 +
  59 + return sanitize_sql(sql)
  60 + end
  61 +
  62 + # Use carefully this method! It might get lost with different classes
  63 + # scopes or different types of joins.
  64 + def or_scope(*scopes)
  65 + where = []
  66 + joins = []
  67 + includes = []
  68 +
  69 + # for some reason, flatten is actually executing the scope
  70 + scopes = scopes[0] if scopes.size == 1
  71 + scopes.each do |s|
  72 + s = s.proxy_options
  73 + begin
  74 + where << merge_conditions(s[:conditions])
  75 + rescue NoMethodError
  76 + # I am ActiveRecord::Base. Only my subclasses define merge_conditions:
  77 + where << subclasses.first.merge_conditions(s[:conditions])
  78 + end
  79 + #where << merge_conditions(s[:conditions])
  80 + joins << s[:joins] unless s[:joins].nil?
  81 + includes << s[:include] unless s[:include].nil?
  82 + end
  83 + scoped = self
  84 + scoped = scoped.select("DISTINCT #{self.table_name}.*")
  85 + scoped = scoped.includes(includes.uniq.flatten) unless includes.blank?
  86 + scoped = scoped.joins(joins.uniq.flatten) unless joins.blank?
  87 + scoped.where(where.join(" OR "))
  88 + end
  89 +
66 90 end
  91 +
67 92 end
68 93 end
69 94 end
... ...