ransack 0.3.0 → 0.4.0
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/ransack/adapters/active_record.rb +3 -4
- data/lib/ransack/adapters/active_record/3.0/compat.rb +143 -0
- data/lib/ransack/adapters/active_record/base.rb +2 -3
- data/lib/ransack/configuration.rb +1 -1
- data/lib/ransack/helpers/form_builder.rb +16 -8
- data/lib/ransack/nodes.rb +1 -2
- data/lib/ransack/nodes/condition.rb +1 -1
- data/lib/ransack/nodes/grouping.rb +31 -56
- data/lib/ransack/predicate.rb +2 -6
- data/lib/ransack/search.rb +3 -3
- data/lib/ransack/translate.rb +1 -1
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +10 -6
- data/spec/ransack/configuration_spec.rb +3 -3
- data/spec/ransack/helpers/form_builder_spec.rb +79 -3
- data/spec/ransack/search_spec.rb +25 -20
- data/spec/spec_helper.rb +1 -0
- data/spec/support/en.yml +5 -0
- metadata +4 -5
- data/lib/ransack/adapters/active_record/3.0/base.rb +0 -33
- data/lib/ransack/nodes/and.rb +0 -8
- data/lib/ransack/nodes/or.rb +0 -8
@@ -1,18 +1,17 @@
|
|
1
|
+
require 'ransack/adapters/active_record/base'
|
2
|
+
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
|
3
|
+
|
1
4
|
case ActiveRecord::VERSION::STRING
|
2
5
|
when /^3\.0\./
|
3
|
-
require 'ransack/adapters/active_record/3.0/base'
|
4
6
|
require 'ransack/adapters/active_record/3.0/join_dependency'
|
5
7
|
require 'ransack/adapters/active_record/3.0/join_association'
|
6
8
|
require 'ransack/adapters/active_record/3.0/context'
|
7
9
|
|
8
|
-
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
|
9
10
|
ActiveRecord::Associations::ClassMethods::JoinDependency.send :include, Ransack::Adapters::ActiveRecord::JoinDependency
|
10
11
|
else
|
11
|
-
require 'ransack/adapters/active_record/base'
|
12
12
|
require 'ransack/adapters/active_record/join_dependency'
|
13
13
|
require 'ransack/adapters/active_record/join_association'
|
14
14
|
require 'ransack/adapters/active_record/context'
|
15
15
|
|
16
|
-
ActiveRecord::Base.extend Ransack::Adapters::ActiveRecord::Base
|
17
16
|
ActiveRecord::Associations::JoinDependency.send :include, Ransack::Adapters::ActiveRecord::JoinDependency
|
18
17
|
end
|
@@ -20,4 +20,147 @@ class ::ActiveRecord::Associations::ClassMethods::JoinDependency::JoinBase
|
|
20
20
|
:engine => active_record.arel_engine,
|
21
21
|
:columns => active_record.columns)
|
22
22
|
end
|
23
|
+
end
|
24
|
+
|
25
|
+
module Arel
|
26
|
+
|
27
|
+
class Table
|
28
|
+
alias :table_name :name
|
29
|
+
|
30
|
+
def [] name
|
31
|
+
::Arel::Attribute.new self, name.to_sym
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
module Nodes
|
36
|
+
class Node
|
37
|
+
def not
|
38
|
+
Nodes::Not.new self
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
remove_const :And
|
43
|
+
class And < Arel::Nodes::Node
|
44
|
+
attr_reader :children
|
45
|
+
|
46
|
+
def initialize children, right = nil
|
47
|
+
unless Array === children
|
48
|
+
children = [children, right]
|
49
|
+
end
|
50
|
+
@children = children
|
51
|
+
end
|
52
|
+
|
53
|
+
def left
|
54
|
+
children.first
|
55
|
+
end
|
56
|
+
|
57
|
+
def right
|
58
|
+
children[1]
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class NamedFunction < Arel::Nodes::Function
|
63
|
+
attr_accessor :name, :distinct
|
64
|
+
|
65
|
+
include Arel::Predications
|
66
|
+
|
67
|
+
def initialize name, expr, aliaz = nil
|
68
|
+
super(expr, aliaz)
|
69
|
+
@name = name
|
70
|
+
@distinct = false
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
class InfixOperation < Binary
|
75
|
+
include Arel::Expressions
|
76
|
+
include Arel::Predications
|
77
|
+
|
78
|
+
attr_reader :operator
|
79
|
+
|
80
|
+
def initialize operator, left, right
|
81
|
+
super(left, right)
|
82
|
+
@operator = operator
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
class Multiplication < InfixOperation
|
87
|
+
def initialize left, right
|
88
|
+
super(:*, left, right)
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
class Division < InfixOperation
|
93
|
+
def initialize left, right
|
94
|
+
super(:/, left, right)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
class Addition < InfixOperation
|
99
|
+
def initialize left, right
|
100
|
+
super(:+, left, right)
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
class Subtraction < InfixOperation
|
105
|
+
def initialize left, right
|
106
|
+
super(:-, left, right)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
module Visitors
|
112
|
+
class ToSql
|
113
|
+
def column_for attr
|
114
|
+
name = attr.name.to_s
|
115
|
+
table = attr.relation.table_name
|
116
|
+
|
117
|
+
column_cache[table][name]
|
118
|
+
end
|
119
|
+
|
120
|
+
def column_cache
|
121
|
+
@column_cache ||= Hash.new do |hash, key|
|
122
|
+
hash[key] = Hash[
|
123
|
+
@engine.connection.columns(key, "#{key} Columns").map do |c|
|
124
|
+
[c.name, c]
|
125
|
+
end
|
126
|
+
]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def visit_Arel_Nodes_InfixOperation o
|
131
|
+
"#{visit o.left} #{o.operator} #{visit o.right}"
|
132
|
+
end
|
133
|
+
|
134
|
+
def visit_Arel_Nodes_NamedFunction o
|
135
|
+
"#{o.name}(#{o.distinct ? 'DISTINCT ' : ''}#{o.expressions.map { |x|
|
136
|
+
visit x
|
137
|
+
}.join(', ')})#{o.alias ? " AS #{visit o.alias}" : ''}"
|
138
|
+
end
|
139
|
+
|
140
|
+
def visit_Arel_Nodes_And o
|
141
|
+
o.children.map { |x| visit x }.join ' AND '
|
142
|
+
end
|
143
|
+
|
144
|
+
def visit_Arel_Nodes_Not o
|
145
|
+
"NOT (#{visit o.expr})"
|
146
|
+
end
|
147
|
+
|
148
|
+
def visit_Arel_Nodes_Values o
|
149
|
+
"VALUES (#{o.expressions.zip(o.columns).map { |value, attr|
|
150
|
+
if Nodes::SqlLiteral === value
|
151
|
+
visit_Arel_Nodes_SqlLiteral value
|
152
|
+
else
|
153
|
+
quote(value, attr && column_for(attr))
|
154
|
+
end
|
155
|
+
}.join ', '})"
|
156
|
+
end
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
module Predications
|
161
|
+
def as other
|
162
|
+
Nodes::As.new self, Nodes::SqlLiteral.new(other)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
|
23
166
|
end
|
@@ -19,12 +19,11 @@ module Ransack
|
|
19
19
|
Ransacker.new(self, name, opts, &block)
|
20
20
|
end
|
21
21
|
|
22
|
-
|
23
|
-
def ransackable_attributes(auth_object)
|
22
|
+
def ransackable_attributes(auth_object = nil)
|
24
23
|
column_names + _ransackers.keys
|
25
24
|
end
|
26
25
|
|
27
|
-
def ransackable_associations(auth_object)
|
26
|
+
def ransackable_associations(auth_object = nil)
|
28
27
|
reflect_on_all_associations.map {|a| a.name.to_s}
|
29
28
|
end
|
30
29
|
|
@@ -77,12 +77,8 @@ module Ransack
|
|
77
77
|
search_fields(:c, args, block)
|
78
78
|
end
|
79
79
|
|
80
|
-
def
|
81
|
-
search_fields(:
|
82
|
-
end
|
83
|
-
|
84
|
-
def or_fields(*args, &block)
|
85
|
-
search_fields(:o, args, block)
|
80
|
+
def grouping_fields(*args, &block)
|
81
|
+
search_fields(:g, args, block)
|
86
82
|
end
|
87
83
|
|
88
84
|
def attribute_fields(*args, &block)
|
@@ -114,15 +110,27 @@ module Ransack
|
|
114
110
|
end
|
115
111
|
|
116
112
|
def predicate_select(options = {}, html_options = {})
|
113
|
+
options[:compounds] = true if options[:compounds].nil?
|
114
|
+
keys = options[:compounds] ? Ransack.predicate_keys : Ransack.predicate_keys.reject {|k| k.match(/_(any|all)$/)}
|
115
|
+
if only = options[:only]
|
116
|
+
if only.respond_to? :call
|
117
|
+
keys = keys.select {|k| only.call(k)}
|
118
|
+
else
|
119
|
+
only = Array.wrap(only).map(&:to_s)
|
120
|
+
keys = keys.select {|k| only.include? k.sub(/_(any|all)$/, '')}
|
121
|
+
end
|
122
|
+
end
|
123
|
+
|
117
124
|
@template.collection_select(
|
118
|
-
@object_name, :p,
|
125
|
+
@object_name, :p, keys.map {|k| [k, Translate.predicate(k)]}, :first, :last,
|
119
126
|
objectify_options(options), @default_options.merge(html_options)
|
120
127
|
)
|
121
128
|
end
|
122
129
|
|
123
130
|
def combinator_select(options = {}, html_options = {})
|
131
|
+
choices = Nodes::Condition === object ? [:or, :and] : [:and, :or]
|
124
132
|
@template.collection_select(
|
125
|
-
@object_name, :m,
|
133
|
+
@object_name, :m, choices.map {|o| [o.to_s, Translate.word(o)]}, :first, :last,
|
126
134
|
objectify_options(options), @default_options.merge(html_options)
|
127
135
|
)
|
128
136
|
end
|
data/lib/ransack/nodes.rb
CHANGED
@@ -28,7 +28,7 @@ module Ransack
|
|
28
28
|
|
29
29
|
def extract_attributes_and_predicate(key)
|
30
30
|
str = key.dup
|
31
|
-
name = Ransack
|
31
|
+
name = Ransack.predicate_keys.detect {|p| str.sub!(/_#{p}$/, '')}
|
32
32
|
predicate = Predicate.named(name)
|
33
33
|
raise ArgumentError, "No valid predicate for #{key}" unless predicate
|
34
34
|
attributes = str.split(/_and_|_or_/)
|
@@ -2,11 +2,20 @@ module Ransack
|
|
2
2
|
module Nodes
|
3
3
|
class Grouping < Node
|
4
4
|
attr_reader :conditions
|
5
|
+
attr_accessor :combinator
|
6
|
+
alias :m :combinator
|
7
|
+
alias :m= :combinator=
|
8
|
+
|
5
9
|
i18n_word :condition, :and, :or
|
6
10
|
i18n_alias :c => :condition, :n => :and, :o => :or
|
7
11
|
|
8
12
|
delegate :each, :to => :values
|
9
13
|
|
14
|
+
def initialize(context, combinator = nil)
|
15
|
+
super(context)
|
16
|
+
self.combinator = combinator.to_s if combinator
|
17
|
+
end
|
18
|
+
|
10
19
|
def persisted?
|
11
20
|
false
|
12
21
|
end
|
@@ -52,7 +61,7 @@ module Ransack
|
|
52
61
|
end
|
53
62
|
|
54
63
|
def values
|
55
|
-
conditions +
|
64
|
+
conditions + groupings
|
56
65
|
end
|
57
66
|
|
58
67
|
def respond_to?(method_id)
|
@@ -79,51 +88,28 @@ module Ransack
|
|
79
88
|
condition
|
80
89
|
end
|
81
90
|
|
82
|
-
def
|
83
|
-
@
|
91
|
+
def groupings
|
92
|
+
@groupings ||= []
|
84
93
|
end
|
85
|
-
alias :
|
94
|
+
alias :g :groupings
|
86
95
|
|
87
|
-
def
|
88
|
-
case
|
96
|
+
def groupings=(groupings)
|
97
|
+
case groupings
|
89
98
|
when Array
|
90
|
-
|
91
|
-
|
92
|
-
self.
|
99
|
+
groupings.each do |attrs|
|
100
|
+
grouping_object = new_grouping(attrs)
|
101
|
+
self.groupings << grouping_object if grouping_object.values.any?
|
93
102
|
end
|
94
103
|
when Hash
|
95
|
-
|
96
|
-
|
97
|
-
self.
|
104
|
+
groupings.each do |index, attrs|
|
105
|
+
grouping_object = new_grouping(attrs)
|
106
|
+
self.groupings << grouping_object if grouping_object.values.any?
|
98
107
|
end
|
99
108
|
else
|
100
|
-
raise ArgumentError, "Invalid argument (#{
|
109
|
+
raise ArgumentError, "Invalid argument (#{groupings.class}) supplied to groupings="
|
101
110
|
end
|
102
111
|
end
|
103
|
-
alias :
|
104
|
-
|
105
|
-
def ors
|
106
|
-
@ors ||= []
|
107
|
-
end
|
108
|
-
alias :o :ors
|
109
|
-
|
110
|
-
def ors=(ors)
|
111
|
-
case ors
|
112
|
-
when Array
|
113
|
-
ors.each do |attrs|
|
114
|
-
or_object = Or.new(@context).build(attrs)
|
115
|
-
self.ors << or_object if or_object.values.any?
|
116
|
-
end
|
117
|
-
when Hash
|
118
|
-
ors.each do |index, attrs|
|
119
|
-
or_object = Or.new(@context).build(attrs)
|
120
|
-
self.ors << or_object if or_object.values.any?
|
121
|
-
end
|
122
|
-
else
|
123
|
-
raise ArgumentError, "Invalid argument (#{ors.class}) supplied to ors="
|
124
|
-
end
|
125
|
-
end
|
126
|
-
alias :o= :ors=
|
112
|
+
alias :g= :groupings=
|
127
113
|
|
128
114
|
def method_missing(method_id, *args)
|
129
115
|
method_name = method_id.to_s
|
@@ -138,39 +124,28 @@ module Ransack
|
|
138
124
|
def attribute_method?(name)
|
139
125
|
name = strip_predicate_and_index(name)
|
140
126
|
case name
|
141
|
-
when /^(
|
127
|
+
when /^(g|c|m|groupings|conditions|combinator)=?$/
|
142
128
|
true
|
143
129
|
else
|
144
130
|
name.split(/_and_|_or_/).select {|n| !@context.attribute_method?(n)}.empty?
|
145
131
|
end
|
146
132
|
end
|
147
133
|
|
148
|
-
def
|
149
|
-
params ||= {}
|
150
|
-
new_and(params).tap do |new_and|
|
151
|
-
self.ands << new_and
|
152
|
-
end
|
153
|
-
end
|
154
|
-
|
155
|
-
def new_and(params = {})
|
156
|
-
And.new(@context).build(params)
|
157
|
-
end
|
158
|
-
|
159
|
-
def build_or(params = {})
|
134
|
+
def build_grouping(params = {})
|
160
135
|
params ||= {}
|
161
|
-
|
162
|
-
self.
|
136
|
+
new_grouping(params).tap do |new_grouping|
|
137
|
+
self.groupings << new_grouping
|
163
138
|
end
|
164
139
|
end
|
165
140
|
|
166
|
-
def
|
167
|
-
|
141
|
+
def new_grouping(params = {})
|
142
|
+
Grouping.new(@context).build(params)
|
168
143
|
end
|
169
144
|
|
170
145
|
def build(params)
|
171
146
|
params.with_indifferent_access.each do |key, value|
|
172
147
|
case key
|
173
|
-
when /^(
|
148
|
+
when /^(g|c|m)$/
|
174
149
|
self.send("#{key}=", value)
|
175
150
|
else
|
176
151
|
write_attribute(key.to_s, value)
|
@@ -198,7 +173,7 @@ module Ransack
|
|
198
173
|
|
199
174
|
def strip_predicate_and_index(str)
|
200
175
|
string = str.split(/\(/).first
|
201
|
-
Ransack
|
176
|
+
Ransack.predicate_keys.detect {|p| string.sub!(/_#{p}$/, '')}
|
202
177
|
string
|
203
178
|
end
|
204
179
|
|
data/lib/ransack/predicate.rb
CHANGED
@@ -4,15 +4,11 @@ module Ransack
|
|
4
4
|
|
5
5
|
class << self
|
6
6
|
def named(name)
|
7
|
-
|
7
|
+
Ransack.predicates[name.to_s]
|
8
8
|
end
|
9
9
|
|
10
10
|
def for_attribute_name(attribute_name)
|
11
|
-
self.named(
|
12
|
-
end
|
13
|
-
|
14
|
-
def collection
|
15
|
-
Configuration.predicates.map {|k, v| [k, Translate.predicate(k)]}
|
11
|
+
self.named(Ransack.predicate_keys.detect {|p| attribute_name.to_s.match(/_#{p}$/)})
|
16
12
|
end
|
17
13
|
end
|
18
14
|
|
data/lib/ransack/search.rb
CHANGED
@@ -9,15 +9,15 @@ module Ransack
|
|
9
9
|
attr_reader :base, :context
|
10
10
|
|
11
11
|
delegate :object, :klass, :to => :context
|
12
|
-
delegate :
|
13
|
-
:
|
12
|
+
delegate :new_grouping, :new_condition,
|
13
|
+
:build_grouping, :build_condition,
|
14
14
|
:translate, :to => :base
|
15
15
|
|
16
16
|
def initialize(object, params = {}, options = {})
|
17
17
|
params ||= {}
|
18
18
|
@context = Context.for(object)
|
19
19
|
@context.auth_object = options[:auth_object]
|
20
|
-
@base = Nodes::
|
20
|
+
@base = Nodes::Grouping.new(@context, 'and')
|
21
21
|
build(params.with_indifferent_access)
|
22
22
|
end
|
23
23
|
|
data/lib/ransack/translate.rb
CHANGED
@@ -18,7 +18,7 @@ module Ransack
|
|
18
18
|
original_name = key.to_s
|
19
19
|
base_class = context.klass
|
20
20
|
base_ancestors = base_class.ancestors.select { |x| x.respond_to?(:model_name) }
|
21
|
-
predicate = Ransack
|
21
|
+
predicate = Ransack.predicate_keys.detect {|p| original_name.match(/_#{p}$/)}
|
22
22
|
attributes_str = original_name.sub(/_#{predicate}$/, '')
|
23
23
|
attribute_names = attributes_str.split(/_and_|_or_/)
|
24
24
|
combinator = attributes_str.match(/_and_/) ? :and : :or
|
data/lib/ransack/version.rb
CHANGED
data/lib/ransack/visitor.rb
CHANGED
@@ -17,7 +17,11 @@ module Ransack
|
|
17
17
|
object.arel_predicate if object.valid?
|
18
18
|
end
|
19
19
|
|
20
|
-
def
|
20
|
+
def visit_Ransack_Nodes_Grouping(object)
|
21
|
+
object.combinator == 'or' ? visit_or(object) : visit_and(object)
|
22
|
+
end
|
23
|
+
|
24
|
+
def visit_and(object)
|
21
25
|
nodes = object.values.map {|o| accept(o)}.compact
|
22
26
|
return nil unless nodes.size > 0
|
23
27
|
|
@@ -28,11 +32,7 @@ module Ransack
|
|
28
32
|
end
|
29
33
|
end
|
30
34
|
|
31
|
-
def
|
32
|
-
object.attr.send(object.dir) if object.valid?
|
33
|
-
end
|
34
|
-
|
35
|
-
def visit_Ransack_Nodes_Or(object)
|
35
|
+
def visit_or(object)
|
36
36
|
nodes = object.values.map {|o| accept(o)}.compact
|
37
37
|
return nil unless nodes.size > 0
|
38
38
|
|
@@ -43,6 +43,10 @@ module Ransack
|
|
43
43
|
end
|
44
44
|
end
|
45
45
|
|
46
|
+
def visit_Ransack_Nodes_Sort(object)
|
47
|
+
object.attr.send(object.dir) if object.valid?
|
48
|
+
end
|
49
|
+
|
46
50
|
def quoted?(object)
|
47
51
|
case object
|
48
52
|
when Arel::Nodes::SqlLiteral, Bignum, Fixnum
|
@@ -2,9 +2,9 @@ require 'spec_helper'
|
|
2
2
|
|
3
3
|
module Ransack
|
4
4
|
describe Configuration do
|
5
|
-
it 'yields
|
6
|
-
Ransack.configure do
|
7
|
-
|
5
|
+
it 'yields Ransack on configure' do
|
6
|
+
Ransack.configure do |config|
|
7
|
+
config.should eq Ransack
|
8
8
|
end
|
9
9
|
end
|
10
10
|
end
|
@@ -32,12 +32,88 @@ module Ransack
|
|
32
32
|
|
33
33
|
it 'selects previously-entered time values with datetime_select' do
|
34
34
|
@s.created_at_eq = [2011, 1, 2, 3, 4, 5]
|
35
|
-
html = @f.datetime_select :created_at_eq
|
36
|
-
|
37
|
-
html.should match /<option selected="selected" value="#{val}">#{val}<\/option>/
|
35
|
+
html = @f.datetime_select :created_at_eq, :use_month_numbers => true, :include_seconds => true
|
36
|
+
%w(2011 1 2 03 04 05).each do |val|
|
37
|
+
html.should match /<option selected="selected" value="#{val}">#{val}<\/option>/
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
describe '#label' do
|
42
|
+
|
43
|
+
it 'localizes attribute names' do
|
44
|
+
html = @f.label :name_cont
|
45
|
+
html.should match /Full Name contains/
|
46
|
+
end
|
47
|
+
|
48
|
+
end
|
49
|
+
|
50
|
+
describe '#submit' do
|
51
|
+
|
52
|
+
it 'localizes :search when no default value given' do
|
53
|
+
html = @f.submit
|
54
|
+
html.should match /"Search"/
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
describe '#attribute_select' do
|
60
|
+
|
61
|
+
it 'returns ransackable attributes' do
|
62
|
+
html = @f.attribute_select
|
63
|
+
html.split(/\n/).should have(Person.ransackable_attributes.size + 1).lines
|
64
|
+
Person.ransackable_attributes.each do |attribute|
|
65
|
+
html.should match /<option value="#{attribute}">/
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'returns ransackable attributes for associations with :associations' do
|
70
|
+
attributes = Person.ransackable_attributes + Article.ransackable_attributes.map {|a| "articles_#{a}"}
|
71
|
+
html = @f.attribute_select :associations => ['articles']
|
72
|
+
html.split(/\n/).should have(attributes.size).lines
|
73
|
+
attributes.each do |attribute|
|
74
|
+
html.should match /<option value="#{attribute}">/
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'returns option groups for base and associations with :associations' do
|
79
|
+
html = @f.attribute_select :associations => ['articles']
|
80
|
+
[Person, Article].each do |model|
|
81
|
+
html.should match /<optgroup label="#{model}">/
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
end
|
86
|
+
|
87
|
+
describe '#predicate_select' do
|
88
|
+
|
89
|
+
it 'returns predicates with predicate_select' do
|
90
|
+
html = @f.predicate_select
|
91
|
+
Ransack.predicate_keys.each do |key|
|
92
|
+
html.should match /<option value="#{key}">/
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
it 'filters predicates with single-value :only' do
|
97
|
+
html = @f.predicate_select :only => 'eq'
|
98
|
+
Ransack.predicate_keys.reject {|k| k =~ /^eq/}.each do |key|
|
99
|
+
html.should_not match /<option value="#{key}">/
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'filters predicates with multi-value :only' do
|
104
|
+
html = @f.predicate_select :only => [:eq, :lt]
|
105
|
+
Ransack.predicate_keys.reject {|k| k =~ /^(eq|lt)/}.each do |key|
|
106
|
+
html.should_not match /<option value="#{key}">/
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
it 'excludes compounds when :compounds => false' do
|
111
|
+
html = @f.predicate_select :compounds => false
|
112
|
+
Ransack.predicate_keys.select {|k| k =~ /_(any|all)$/}.each do |key|
|
113
|
+
html.should_not match /<option value="#{key}">/
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
41
117
|
end
|
42
118
|
end
|
43
119
|
end
|
data/spec/ransack/search_spec.rb
CHANGED
@@ -39,30 +39,34 @@ module Ransack
|
|
39
39
|
|
40
40
|
it 'accepts arrays of groupings' do
|
41
41
|
search = Search.new(Person,
|
42
|
-
:
|
43
|
-
{:name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
44
|
-
{:name_eq => 'Bert', :children_name_eq => 'Bert'},
|
42
|
+
:g => [
|
43
|
+
{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
44
|
+
{:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'},
|
45
45
|
]
|
46
46
|
)
|
47
|
-
ors = search.
|
47
|
+
ors = search.groupings
|
48
48
|
ors.should have(2).items
|
49
49
|
or1, or2 = ors
|
50
|
-
or1.should be_a Nodes::
|
51
|
-
|
50
|
+
or1.should be_a Nodes::Grouping
|
51
|
+
or1.combinator.should eq 'or'
|
52
|
+
or2.should be_a Nodes::Grouping
|
53
|
+
or2.combinator.should eq 'or'
|
52
54
|
end
|
53
55
|
|
54
56
|
it 'accepts "attributes" hashes for groupings' do
|
55
57
|
search = Search.new(Person,
|
56
|
-
:
|
57
|
-
'0' => {:name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
58
|
-
'1' => {:name_eq => 'Bert', :children_name_eq => 'Bert'},
|
58
|
+
:g => {
|
59
|
+
'0' => {:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
60
|
+
'1' => {:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'},
|
59
61
|
}
|
60
62
|
)
|
61
|
-
ors = search.
|
63
|
+
ors = search.groupings
|
62
64
|
ors.should have(2).items
|
63
65
|
or1, or2 = ors
|
64
|
-
or1.should be_a Nodes::
|
65
|
-
|
66
|
+
or1.should be_a Nodes::Grouping
|
67
|
+
or1.combinator.should eq 'or'
|
68
|
+
or2.should be_a Nodes::Grouping
|
69
|
+
or2.combinator.should eq 'or'
|
66
70
|
end
|
67
71
|
|
68
72
|
it 'accepts "attributes" hashes for conditions' do
|
@@ -102,7 +106,8 @@ module Ransack
|
|
102
106
|
|
103
107
|
it 'evaluates nested conditions' do
|
104
108
|
search = Search.new(Person, :children_name_eq => 'Ernie',
|
105
|
-
:
|
109
|
+
:g => [{
|
110
|
+
:m => 'or',
|
106
111
|
:name_eq => 'Ernie',
|
107
112
|
:children_children_name_eq => 'Ernie'
|
108
113
|
}]
|
@@ -114,9 +119,9 @@ module Ransack
|
|
114
119
|
|
115
120
|
it 'evaluates arrays of groupings' do
|
116
121
|
search = Search.new(Person,
|
117
|
-
:
|
118
|
-
{:name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
119
|
-
{:name_eq => 'Bert', :children_name_eq => 'Bert'},
|
122
|
+
:g => [
|
123
|
+
{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'},
|
124
|
+
{:m => 'or', :name_eq => 'Bert', :children_name_eq => 'Bert'},
|
120
125
|
]
|
121
126
|
)
|
122
127
|
search.result.should be_an ActiveRecord::Relation
|
@@ -125,7 +130,7 @@ module Ransack
|
|
125
130
|
end
|
126
131
|
|
127
132
|
it 'returns distinct records when passed :distinct => true' do
|
128
|
-
search = Search.new(Person, :
|
133
|
+
search = Search.new(Person, :g => [{:m => 'or', :comments_body_cont => 'e', :articles_comments_body_cont => 'e'}])
|
129
134
|
search.result.should have(920).items
|
130
135
|
search.result(:distinct => true).should have(330).items
|
131
136
|
search.result.all.uniq.should eq search.result(:distinct => true).all
|
@@ -195,9 +200,9 @@ module Ransack
|
|
195
200
|
end
|
196
201
|
|
197
202
|
it 'allows chaining to access nested conditions' do
|
198
|
-
@s.
|
199
|
-
@s.
|
200
|
-
@s.
|
203
|
+
@s.groupings = [{:m => 'or', :name_eq => 'Ernie', :children_name_eq => 'Ernie'}]
|
204
|
+
@s.groupings.first.name_eq.should eq 'Ernie'
|
205
|
+
@s.groupings.first.children_name_eq.should eq 'Ernie'
|
201
206
|
end
|
202
207
|
end
|
203
208
|
|
data/spec/spec_helper.rb
CHANGED
data/spec/support/en.yml
ADDED
metadata
CHANGED
@@ -2,7 +2,7 @@
|
|
2
2
|
name: ransack
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.
|
5
|
+
version: 0.4.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Ernie Miller
|
@@ -10,7 +10,7 @@ autorequire:
|
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
12
|
|
13
|
-
date: 2011-05
|
13
|
+
date: 2011-06-05 00:00:00 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activerecord
|
@@ -106,7 +106,6 @@ files:
|
|
106
106
|
- Rakefile
|
107
107
|
- lib/ransack.rb
|
108
108
|
- lib/ransack/adapters/active_record.rb
|
109
|
-
- lib/ransack/adapters/active_record/3.0/base.rb
|
110
109
|
- lib/ransack/adapters/active_record/3.0/compat.rb
|
111
110
|
- lib/ransack/adapters/active_record/3.0/context.rb
|
112
111
|
- lib/ransack/adapters/active_record/3.0/join_association.rb
|
@@ -124,13 +123,11 @@ files:
|
|
124
123
|
- lib/ransack/locale/en.yml
|
125
124
|
- lib/ransack/naming.rb
|
126
125
|
- lib/ransack/nodes.rb
|
127
|
-
- lib/ransack/nodes/and.rb
|
128
126
|
- lib/ransack/nodes/attribute.rb
|
129
127
|
- lib/ransack/nodes/bindable.rb
|
130
128
|
- lib/ransack/nodes/condition.rb
|
131
129
|
- lib/ransack/nodes/grouping.rb
|
132
130
|
- lib/ransack/nodes/node.rb
|
133
|
-
- lib/ransack/nodes/or.rb
|
134
131
|
- lib/ransack/nodes/sort.rb
|
135
132
|
- lib/ransack/nodes/value.rb
|
136
133
|
- lib/ransack/predicate.rb
|
@@ -157,6 +154,7 @@ files:
|
|
157
154
|
- spec/ransack/predicate_spec.rb
|
158
155
|
- spec/ransack/search_spec.rb
|
159
156
|
- spec/spec_helper.rb
|
157
|
+
- spec/support/en.yml
|
160
158
|
- spec/support/schema.rb
|
161
159
|
homepage: http://metautonomo.us/projects/ransack
|
162
160
|
licenses: []
|
@@ -203,4 +201,5 @@ test_files:
|
|
203
201
|
- spec/ransack/predicate_spec.rb
|
204
202
|
- spec/ransack/search_spec.rb
|
205
203
|
- spec/spec_helper.rb
|
204
|
+
- spec/support/en.yml
|
206
205
|
- spec/support/schema.rb
|
@@ -1,33 +0,0 @@
|
|
1
|
-
module Ransack
|
2
|
-
module Adapters
|
3
|
-
module ActiveRecord
|
4
|
-
module Base
|
5
|
-
|
6
|
-
def self.extended(base)
|
7
|
-
alias :search :ransack unless base.method_defined? :search
|
8
|
-
base.instance_eval do
|
9
|
-
class_attribute :_ransackers
|
10
|
-
self._ransackers ||= {}
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def ransack(params = {}, options = {})
|
15
|
-
Search.new(self, params, options)
|
16
|
-
end
|
17
|
-
|
18
|
-
def ransacker(name, opts = {}, &block)
|
19
|
-
Ransacker.new(self, name, opts, &block)
|
20
|
-
end
|
21
|
-
|
22
|
-
def ransackable_attributes(auth_object)
|
23
|
-
column_names + _ransackers.keys
|
24
|
-
end
|
25
|
-
|
26
|
-
def ransackable_associations(auth_object)
|
27
|
-
reflect_on_all_associations.map {|a| a.name.to_s}
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
end
|
32
|
-
end
|
33
|
-
end
|
data/lib/ransack/nodes/and.rb
DELETED