Commit 0b31911bd64211099153a1dd30feede66d6d2a91
Committed by
Daniel
1 parent
b1bcaade
Exists in
master
and in
28 other branches
Make scope unions
closes ActionItem2830
Showing
4 changed files
with
102 additions
and
32 deletions
Show diff stats
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 | ... | ... |
... | ... | @@ -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 | ... | ... |
... | ... | @@ -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 | ... | ... |