ransack 1.8.10 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +0 -1
  3. data/.travis.yml +12 -3
  4. data/CHANGELOG.md +29 -5
  5. data/Gemfile +1 -9
  6. data/README.md +16 -25
  7. data/Rakefile +1 -22
  8. data/lib/polyamorous.rb +5 -18
  9. data/lib/polyamorous/activerecord_5.1_ruby_2/join_dependency.rb +2 -2
  10. data/lib/polyamorous/activerecord_5.2.0_ruby_2/join_dependency.rb +2 -2
  11. data/lib/polyamorous/activerecord_5.2.1_ruby_2/join_association.rb +38 -0
  12. data/lib/polyamorous/activerecord_5.2.1_ruby_2/join_dependency.rb +75 -0
  13. data/lib/ransack/adapters/active_record.rb +0 -9
  14. data/lib/ransack/adapters/active_record/base.rb +8 -0
  15. data/lib/ransack/adapters/active_record/context.rb +118 -182
  16. data/lib/ransack/adapters/active_record/ransack/context.rb +1 -8
  17. data/lib/ransack/adapters/active_record/ransack/translate.rb +1 -5
  18. data/lib/ransack/constants.rb +1 -1
  19. data/lib/ransack/context.rb +4 -0
  20. data/lib/ransack/nodes/value.rb +1 -1
  21. data/lib/ransack/search.rb +1 -1
  22. data/lib/ransack/version.rb +1 -1
  23. data/ransack.gemspec +4 -3
  24. data/spec/helpers/polyamorous_helper.rb +7 -9
  25. data/spec/ransack/adapters/active_record/base_spec.rb +35 -0
  26. data/spec/ransack/adapters/active_record/context_spec.rb +3 -6
  27. data/spec/ransack/helpers/form_builder_spec.rb +3 -15
  28. data/spec/ransack/helpers/form_helper_spec.rb +11 -99
  29. data/spec/ransack/join_association_spec.rb +1 -6
  30. data/spec/ransack/join_dependency_spec.rb +1 -6
  31. data/spec/ransack/search_spec.rb +2 -2
  32. data/spec/support/schema.rb +3 -21
  33. metadata +10 -83
  34. data/lib/polyamorous/activerecord_3_and_4.0_ruby_1.9/join_association.rb +0 -76
  35. data/lib/polyamorous/activerecord_3_and_4.0_ruby_1.9/join_dependency.rb +0 -96
  36. data/lib/polyamorous/activerecord_4.1_ruby_1.9/join_association.rb +0 -2
  37. data/lib/polyamorous/activerecord_4.1_ruby_1.9/join_dependency.rb +0 -4
  38. data/lib/polyamorous/activerecord_4.1_ruby_2/join_association.rb +0 -2
  39. data/lib/polyamorous/activerecord_4.1_ruby_2/join_dependency.rb +0 -3
  40. data/lib/polyamorous/activerecord_4.1_ruby_2/make_polyamorous_inner_joins.rb +0 -14
  41. data/lib/polyamorous/activerecord_4.2_ruby_1.9/join_association.rb +0 -46
  42. data/lib/polyamorous/activerecord_4.2_ruby_1.9/join_dependency.rb +0 -87
  43. data/lib/polyamorous/activerecord_4.2_ruby_2/join_association.rb +0 -2
  44. data/lib/polyamorous/activerecord_4.2_ruby_2/join_dependency.rb +0 -24
  45. data/lib/ransack/adapters/active_record/3.0/compat.rb +0 -173
  46. data/lib/ransack/adapters/active_record/3.0/context.rb +0 -203
  47. data/lib/ransack/adapters/active_record/3.1/context.rb +0 -212
  48. data/lib/ransack/adapters/active_record/3.2/context.rb +0 -44
  49. data/lib/ransack/adapters/mongoid.rb +0 -15
  50. data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
  51. data/lib/ransack/adapters/mongoid/attributes/attribute.rb +0 -37
  52. data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +0 -17
  53. data/lib/ransack/adapters/mongoid/attributes/predications.rb +0 -141
  54. data/lib/ransack/adapters/mongoid/base.rb +0 -134
  55. data/lib/ransack/adapters/mongoid/context.rb +0 -212
  56. data/lib/ransack/adapters/mongoid/inquiry_hash.rb +0 -23
  57. data/lib/ransack/adapters/mongoid/ransack/constants.rb +0 -88
  58. data/lib/ransack/adapters/mongoid/ransack/context.rb +0 -59
  59. data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +0 -22
  60. data/lib/ransack/adapters/mongoid/ransack/translate.rb +0 -13
  61. data/lib/ransack/adapters/mongoid/ransack/visitor.rb +0 -18
  62. data/lib/ransack/adapters/mongoid/table.rb +0 -35
  63. data/spec/mongoid/adapters/mongoid/base_spec.rb +0 -314
  64. data/spec/mongoid/adapters/mongoid/context_spec.rb +0 -56
  65. data/spec/mongoid/configuration_spec.rb +0 -162
  66. data/spec/mongoid/dependencies_spec.rb +0 -8
  67. data/spec/mongoid/helpers/ransack_helper.rb +0 -11
  68. data/spec/mongoid/nodes/condition_spec.rb +0 -49
  69. data/spec/mongoid/nodes/grouping_spec.rb +0 -13
  70. data/spec/mongoid/predicate_spec.rb +0 -155
  71. data/spec/mongoid/search_spec.rb +0 -445
  72. data/spec/mongoid/support/mongoid.yml +0 -11
  73. data/spec/mongoid/support/schema.rb +0 -135
  74. data/spec/mongoid/translate_spec.rb +0 -14
  75. data/spec/mongoid_spec_helper.rb +0 -63
  76. data/spec/ransack/dependencies_spec.rb +0 -12
@@ -1,203 +0,0 @@
1
- require 'ransack/context'
2
- require 'polyamorous'
3
- require 'ransack/adapters/active_record/3.0/compat'
4
-
5
- module Ransack
6
-
7
- module Adapters
8
- module ActiveRecord
9
- class Context < ::Ransack::Context
10
-
11
- # Because the AR::Associations namespace is insane
12
- if defined? ::ActiveRecord::Associations::ClassMethods::JoinDependency
13
- JoinDependency = ::ActiveRecord::Associations::ClassMethods::JoinDependency
14
- end
15
-
16
- # Redefine a few things for ActiveRecord 3.0.
17
-
18
- def initialize(object, options = {})
19
- super
20
- @arel_visitor = Arel::Visitors.visitor_for @engine
21
- end
22
-
23
- def relation_for(object)
24
- object.scoped
25
- end
26
-
27
- def evaluate(search, opts = {})
28
- viz = Visitor.new
29
- relation = @object.where(viz.accept(search.base))
30
- if search.sorts.any?
31
- relation = relation.except(:order)
32
- .reorder(viz.accept(search.sorts))
33
- end
34
- if opts[:distinct]
35
- relation.select(Constants::DISTINCT + @klass.quoted_table_name +
36
- Constants::DOT_ASTERIX)
37
- else
38
- relation
39
- end
40
- end
41
-
42
- def attribute_method?(str, klass = @klass)
43
- exists = false
44
-
45
- if ransackable_attribute?(str, klass)
46
- exists = true
47
- elsif (segments = str.split(Constants::UNDERSCORE)).size > 1
48
- remainder = []
49
- found_assoc = nil
50
- while !found_assoc && remainder.unshift(segments.pop) &&
51
- segments.size > 0 do
52
- assoc, poly_class = unpolymorphize_association(
53
- segments.join(Constants::UNDERSCORE)
54
- )
55
- if found_assoc = get_association(assoc, klass)
56
- exists = attribute_method?(
57
- remainder.join(Constants::UNDERSCORE),
58
- poly_class || found_assoc.klass
59
- )
60
- end
61
- end
62
- end
63
-
64
- exists
65
- end
66
-
67
- def table_for(parent)
68
- parent.table
69
- end
70
-
71
- def type_for(attr)
72
- return nil unless attr && attr.valid?
73
- klassify(attr.parent)
74
- .columns_hash[attr.arel_attribute.name.to_s]
75
- .type
76
- end
77
-
78
- # All dependent JoinAssociation items used in the search query
79
- #
80
- def join_associations
81
- @join_dependency.join_associations
82
- end
83
-
84
- def join_sources
85
- raise NotImplementedError,
86
- "ActiveRecord 3.0 does not use join_sources or support joining relations with Arel::Join nodes. Use join_associations."
87
- end
88
-
89
- def alias_tracker
90
- raise NotImplementedError,
91
- "ActiveRecord 3.0 does not have an alias tracker"
92
- end
93
-
94
- private
95
-
96
- def get_parent_and_attribute_name(str, parent = @base)
97
- attr_name = nil
98
-
99
- if ransackable_attribute?(str, klassify(parent))
100
- attr_name = str
101
- elsif (segments = str.split(Constants::UNDERSCORE)).size > 1
102
- remainder = []
103
- found_assoc = nil
104
- while remainder.unshift(segments.pop) && segments.size > 0 &&
105
- !found_assoc do
106
- assoc, klass = unpolymorphize_association(
107
- segments.join(Constants::UNDERSCORE)
108
- )
109
- if found_assoc = get_association(assoc, parent)
110
- join = build_or_find_association(
111
- found_assoc.name, parent, klass
112
- )
113
- parent, attr_name = get_parent_and_attribute_name(
114
- remainder.join(Constants::UNDERSCORE), join
115
- )
116
- end
117
- end
118
- end
119
- [parent, attr_name]
120
- end
121
-
122
- def get_association(str, parent = @base)
123
- klass = klassify parent
124
- ransackable_association?(str, klass) &&
125
- klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
126
- end
127
-
128
- def join_dependency(relation)
129
- if relation.respond_to?(:join_dependency) # Polyamorous enables this
130
- relation.join_dependency
131
- else
132
- build_join_dependency(relation)
133
- end
134
- end
135
-
136
- def build_join_dependency(relation)
137
- buckets = relation.joins_values.group_by do |join|
138
- case join
139
- when String
140
- Constants::STRING_JOIN
141
- when Hash, Symbol, Array
142
- Constants::ASSOCIATION_JOIN
143
- when ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinAssociation
144
- Constants::STASHED_JOIN
145
- when Arel::Nodes::Join
146
- Constants::JOIN_NODE
147
- else
148
- raise 'unknown class: %s' % join.class.name
149
- end
150
- end
151
-
152
- association_joins = buckets[Constants::ASSOCIATION_JOIN] || []
153
-
154
- stashed_association_joins = buckets[Constants::STASHED_JOIN] || []
155
-
156
- join_nodes = buckets[Constants::JOIN_NODE] || []
157
-
158
- string_joins = (buckets[Constants::STRING_JOIN] || []).map(&:strip).uniq
159
-
160
- join_list = relation.send :custom_join_sql, (string_joins + join_nodes)
161
-
162
- join_dependency = JoinDependency.new(
163
- relation.klass,
164
- association_joins,
165
- join_list
166
- )
167
-
168
- join_nodes.each do |join|
169
- join_dependency.table_aliases[join.left.name.downcase] = 1
170
- end
171
-
172
- join_dependency.graft(*stashed_association_joins)
173
- end
174
-
175
- def build_or_find_association(name, parent = @base, klass = nil)
176
- found_association = @join_dependency.join_associations
177
- .detect do |assoc|
178
- assoc.reflection.name == name &&
179
- assoc.parent == parent &&
180
- (!klass || assoc.reflection.klass == klass)
181
- end
182
- unless found_association
183
- @join_dependency.send(
184
- :build, Polyamorous::Join.new(name, @join_type, klass), parent
185
- )
186
- found_association = @join_dependency.join_associations.last
187
-
188
- default_conditions = found_association.active_record.scoped.arel.constraints
189
- if default_conditions.any?
190
- and_default_conditions = "AND #{default_conditions.reduce(&:and).to_sql}"
191
- end
192
-
193
- # Leverage the stashed association functionality in AR
194
- @object = @object.joins(found_association).joins(and_default_conditions)
195
- end
196
-
197
- found_association
198
- end
199
-
200
- end
201
- end
202
- end
203
- end
@@ -1,212 +0,0 @@
1
- require 'ransack/context'
2
- require 'ransack/adapters/active_record/compat'
3
- require 'polyamorous'
4
-
5
- module Ransack
6
- module Adapters
7
- module ActiveRecord
8
- class Context < ::Ransack::Context
9
-
10
- # Redefine a few things for ActiveRecord 3.1.
11
-
12
- def initialize(object, options = {})
13
- super
14
- @arel_visitor = Arel::Visitors.visitor_for @engine
15
- end
16
-
17
- def relation_for(object)
18
- object.scoped
19
- end
20
-
21
- def evaluate(search, opts = {})
22
- viz = Visitor.new
23
- relation = @object.where(viz.accept(search.base))
24
- if search.sorts.any?
25
- relation = relation.except(:order)
26
- .reorder(viz.accept(search.sorts))
27
- end
28
- if opts[:distinct]
29
- relation.select(Constants::DISTINCT + @klass.quoted_table_name +
30
- Constants::DOT_ASTERIX)
31
- else
32
- relation
33
- end
34
- end
35
-
36
- def attribute_method?(str, klass = @klass)
37
- exists = false
38
-
39
- if ransackable_attribute?(str, klass)
40
- exists = true
41
- elsif (segments = str.split(Constants::UNDERSCORE)).size > 1
42
- remainder = []
43
- found_assoc = nil
44
- while !found_assoc && remainder.unshift(segments.pop) &&
45
- segments.size > 0 do
46
- assoc, poly_class = unpolymorphize_association(
47
- segments.join(Constants::UNDERSCORE)
48
- )
49
- if found_assoc = get_association(assoc, klass)
50
- exists = attribute_method?(
51
- remainder.join(Constants::UNDERSCORE),
52
- poly_class || found_assoc.klass
53
- )
54
- end
55
- end
56
- end
57
-
58
- exists
59
- end
60
-
61
- def table_for(parent)
62
- parent.table
63
- end
64
-
65
- def type_for(attr)
66
- return nil unless attr && attr.valid?
67
- name = attr.arel_attribute.name.to_s
68
- table = attr.arel_attribute.relation.table_name
69
-
70
- unless @engine.connection_pool.table_exists?(table)
71
- raise "No table named #{table} exists"
72
- end
73
-
74
- @engine.connection_pool.columns_hash[table][name].type
75
- end
76
-
77
- def join_associations
78
- @join_dependency.join_associations
79
- end
80
-
81
- # All dependent Arel::Join nodes used in the search query
82
- #
83
- # This could otherwise be done as `@object.arel.join_sources`, except
84
- # that ActiveRecord's build_joins sets up its own JoinDependency.
85
- # This extracts what we need to access the joins using our existing
86
- # JoinDependency to track table aliases.
87
- #
88
- def join_sources
89
- base = Arel::SelectManager.new(@object.engine, @object.table)
90
- @object.joins_values.each do |assoc|
91
- next unless assoc.is_a?(JoinDependency::JoinAssociation)
92
- assoc.join_to(base)
93
- end
94
- base.join_sources
95
- end
96
-
97
- def alias_tracker
98
- @join_dependency.alias_tracker
99
- end
100
-
101
- private
102
-
103
- def get_parent_and_attribute_name(str, parent = @base)
104
- attr_name = nil
105
-
106
- if ransackable_attribute?(str, klassify(parent))
107
- attr_name = str
108
- elsif (segments = str.split(Constants::UNDERSCORE)).size > 1
109
- remainder = []
110
- found_assoc = nil
111
- while remainder.unshift(segments.pop) && segments.size > 0 &&
112
- !found_assoc do
113
- assoc, klass = unpolymorphize_association(
114
- segments.join(Constants::UNDERSCORE)
115
- )
116
- if found_assoc = get_association(assoc, parent)
117
- join = build_or_find_association(
118
- found_assoc.name, parent, klass
119
- )
120
- parent, attr_name = get_parent_and_attribute_name(
121
- remainder.join(Constants::UNDERSCORE), join
122
- )
123
- end
124
- end
125
- end
126
-
127
- [parent, attr_name]
128
- end
129
-
130
- def get_association(str, parent = @base)
131
- klass = klassify parent
132
- ransackable_association?(str, klass) &&
133
- klass.reflect_on_all_associations.detect { |a| a.name.to_s == str }
134
- end
135
-
136
- def join_dependency(relation)
137
- if relation.respond_to?(:join_dependency) # Polyamorous enables this
138
- relation.join_dependency
139
- else
140
- build_join_dependency(relation)
141
- end
142
- end
143
-
144
- def build_join_dependency(relation)
145
- buckets = relation.joins_values.group_by do |join|
146
- case join
147
- when String
148
- Constants::STRING_JOIN
149
- when Hash, Symbol, Array
150
- Constants::ASSOCIATION_JOIN
151
- when JoinDependency::JoinAssociation
152
- Constants::STASHED_JOIN
153
- when Arel::Nodes::Join
154
- Constants::JOIN_NODE
155
- else
156
- raise 'unknown class: %s' % join.class.name
157
- end
158
- end
159
-
160
- association_joins = buckets[Constants::ASSOCIATION_JOIN] || []
161
-
162
- stashed_association_joins = buckets[Constants::STASHED_JOIN] || []
163
-
164
- join_nodes = buckets[Constants::JOIN_NODE] || []
165
-
166
- string_joins = (buckets[Constants::STRING_JOIN] || []).map(&:strip).uniq
167
-
168
- join_list = relation.send :custom_join_ast,
169
- relation.table.from(relation.table), string_joins
170
-
171
- join_dependency = JoinDependency.new(
172
- relation.klass,
173
- association_joins,
174
- join_list
175
- )
176
-
177
- join_nodes.each do |join|
178
- join_dependency.alias_tracker.aliases[join.left.name.downcase] = 1
179
- end
180
-
181
- join_dependency.graft(*stashed_association_joins)
182
- end
183
-
184
- def build_or_find_association(name, parent = @base, klass = nil)
185
- found_association = @join_dependency.join_associations
186
- .detect do |assoc|
187
- assoc.reflection.name == name &&
188
- assoc.parent == parent &&
189
- (!klass || assoc.reflection.klass == klass)
190
- end
191
- unless found_association
192
- @join_dependency.send(
193
- :build, Polyamorous::Join.new(name, @join_type, klass), parent
194
- )
195
- found_association = @join_dependency.join_associations.last
196
-
197
- default_conditions = found_association.active_record.scoped.arel.constraints
198
- if default_conditions.any?
199
- and_default_conditions = "AND #{default_conditions.reduce(&:and).to_sql}"
200
- end
201
-
202
- # Leverage the stashed association functionality in AR
203
- @object = @object.joins(found_association).joins(and_default_conditions)
204
- end
205
-
206
- found_association
207
- end
208
-
209
- end
210
- end
211
- end
212
- end
@@ -1,44 +0,0 @@
1
- require 'ransack/context'
2
- require 'ransack/adapters/active_record/3.1/context'
3
- require 'ransack/adapters/active_record/compat'
4
- require 'polyamorous'
5
-
6
- module Ransack
7
- module Adapters
8
- module ActiveRecord
9
- class Context < ::Ransack::Context
10
-
11
- # Redefine a few things for ActiveRecord 3.2.
12
-
13
- def initialize(object, options = {})
14
- super
15
- @arel_visitor = @engine.connection.visitor
16
- end
17
-
18
- def relation_for(object)
19
- object.scoped
20
- end
21
-
22
- def type_for(attr)
23
- return nil unless attr && attr.valid?
24
- name = attr.arel_attribute.name.to_s
25
- table = attr.arel_attribute.relation.table_name
26
-
27
- schema_cache = @engine.connection.schema_cache
28
- raise "No table named #{table} exists" unless schema_cache.table_exists?(table)
29
- schema_cache.columns_hash[table][name].type
30
- end
31
-
32
- def evaluate(search, opts = {})
33
- viz = Visitor.new
34
- relation = @object.where(viz.accept(search.base))
35
- if search.sorts.any?
36
- relation = relation.except(:order).reorder(viz.accept(search.sorts))
37
- end
38
- opts[:distinct] ? relation.uniq : relation
39
- end
40
-
41
- end
42
- end
43
- end
44
- end