ransack 1.8.10 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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