ransack 0.3.0 → 0.4.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.
- 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