ransack 1.7.0 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +4 -4
  2. data/.travis.yml +40 -22
  3. data/CHANGELOG.md +176 -27
  4. data/CONTRIBUTING.md +30 -19
  5. data/Gemfile +8 -3
  6. data/README.md +131 -58
  7. data/Rakefile +5 -2
  8. data/lib/ransack.rb +10 -5
  9. data/lib/ransack/adapters.rb +43 -23
  10. data/lib/ransack/adapters/active_record.rb +2 -2
  11. data/lib/ransack/adapters/active_record/3.0/compat.rb +5 -5
  12. data/lib/ransack/adapters/active_record/3.0/context.rb +5 -3
  13. data/lib/ransack/adapters/active_record/3.1/context.rb +1 -4
  14. data/lib/ransack/adapters/active_record/base.rb +12 -1
  15. data/lib/ransack/adapters/active_record/context.rb +148 -55
  16. data/lib/ransack/adapters/active_record/ransack/constants.rb +53 -53
  17. data/lib/ransack/adapters/active_record/ransack/context.rb +3 -1
  18. data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +20 -28
  19. data/lib/ransack/adapters/mongoid/base.rb +21 -6
  20. data/lib/ransack/adapters/mongoid/context.rb +9 -5
  21. data/lib/ransack/configuration.rb +24 -3
  22. data/lib/ransack/constants.rb +11 -22
  23. data/lib/ransack/context.rb +20 -13
  24. data/lib/ransack/helpers/form_builder.rb +5 -6
  25. data/lib/ransack/helpers/form_helper.rb +50 -69
  26. data/lib/ransack/locale/da.yml +70 -0
  27. data/lib/ransack/locale/id.yml +70 -0
  28. data/lib/ransack/locale/ja.yml +70 -0
  29. data/lib/ransack/locale/pt-BR.yml +70 -0
  30. data/lib/ransack/locale/{zh.yml → zh-CN.yml} +1 -1
  31. data/lib/ransack/locale/zh-TW.yml +70 -0
  32. data/lib/ransack/nodes.rb +1 -1
  33. data/lib/ransack/nodes/attribute.rb +4 -1
  34. data/lib/ransack/nodes/bindable.rb +18 -6
  35. data/lib/ransack/nodes/condition.rb +58 -28
  36. data/lib/ransack/nodes/grouping.rb +15 -4
  37. data/lib/ransack/nodes/sort.rb +9 -5
  38. data/lib/ransack/predicate.rb +6 -2
  39. data/lib/ransack/search.rb +6 -5
  40. data/lib/ransack/translate.rb +2 -2
  41. data/lib/ransack/version.rb +1 -1
  42. data/ransack.gemspec +4 -4
  43. data/spec/mongoid/adapters/mongoid/base_spec.rb +20 -1
  44. data/spec/mongoid/nodes/condition_spec.rb +15 -0
  45. data/spec/mongoid/support/mongoid.yml +5 -0
  46. data/spec/mongoid/support/schema.rb +4 -0
  47. data/spec/mongoid_spec_helper.rb +13 -9
  48. data/spec/ransack/adapters/active_record/base_spec.rb +249 -71
  49. data/spec/ransack/adapters/active_record/context_spec.rb +16 -18
  50. data/spec/ransack/helpers/form_builder_spec.rb +5 -2
  51. data/spec/ransack/helpers/form_helper_spec.rb +84 -14
  52. data/spec/ransack/nodes/condition_spec.rb +24 -0
  53. data/spec/ransack/nodes/grouping_spec.rb +56 -0
  54. data/spec/ransack/predicate_spec.rb +5 -5
  55. data/spec/ransack/search_spec.rb +79 -70
  56. data/spec/support/schema.rb +43 -29
  57. metadata +17 -12
@@ -0,0 +1,70 @@
1
+ da:
2
+ ransack:
3
+ search: "søg"
4
+ predicate: "predicate"
5
+ and: "og"
6
+ or: "eller"
7
+ any: "anhver"
8
+ all: "alle"
9
+ combinator: "kombinering"
10
+ attribute: "attribut"
11
+ value: "værdi"
12
+ condition: "betingelse"
13
+ sort: "sorter"
14
+ asc: "opstigende"
15
+ desc: "faldende"
16
+ predicates:
17
+ eq: "lig med"
18
+ eq_any: "lig med enhver"
19
+ eq_all: "lig med alle"
20
+ not_eq: "ikke lig med"
21
+ not_eq_any: "ikke lig med nogen"
22
+ not_eq_all: "ikke lig med alle"
23
+ matches: "matcher"
24
+ matches_any: "matcher enhver"
25
+ matches_all: "matcher alle"
26
+ does_not_match: "matcher ikke"
27
+ does_not_match_any: "matcher ikke nogen"
28
+ does_not_match_all: "matcher ikke alle"
29
+ lt: "mindre end"
30
+ lt_any: "mindre end nogen"
31
+ lt_all: "mindre end alle"
32
+ lteq: "mindre end eller lig med"
33
+ lteq_any: "mindre end eller lig med nogen"
34
+ lteq_all: "mindre end eller lig med alle"
35
+ gt: "større end"
36
+ gt_any: "større end nogen"
37
+ gt_all: "større end alle"
38
+ gteq: "større end eller lig med"
39
+ gteq_any: "større end eller lig med nogen"
40
+ gteq_all: "større end eller lig med alle"
41
+ in: "i"
42
+ in_any: "i nogen"
43
+ in_all: "i alle"
44
+ not_in: "ikke i"
45
+ not_in_any: "ikke i nogen"
46
+ not_in_all: "ikke i alle"
47
+ cont: "indeholder"
48
+ cont_any: "indeholder nogen"
49
+ cont_all: "indeholder alle"
50
+ not_cont: "indeholder ikke"
51
+ not_cont_any: "indeholder ikke nogen"
52
+ not_cont_all: "indeholder ikke alle"
53
+ start: "starter med"
54
+ start_any: "starter med nogen"
55
+ start_all: "starter med alle"
56
+ not_start: "starter ikke med"
57
+ not_start_any: "starter ikke med nogen"
58
+ not_start_all: "starter ikke med alle"
59
+ end: "slutter med"
60
+ end_any: "slutter med nogen"
61
+ end_all: "slutter med alle"
62
+ not_end: "slutter ikke med"
63
+ not_end_any: "slutter ikke med nogen"
64
+ not_end_all: "slutter ikke med alle"
65
+ 'true': "er sand"
66
+ 'false': "er falsk"
67
+ present: "er til stede"
68
+ blank: "er blank"
69
+ 'null': "er nul"
70
+ not_null: "er ikke nul"
@@ -0,0 +1,70 @@
1
+ id:
2
+ ransack:
3
+ search: "cari"
4
+ predicate: "predikat"
5
+ and: "dan"
6
+ or: "atau"
7
+ any: "apapun"
8
+ all: "semua"
9
+ combinator: "kombinasi"
10
+ attribute: "atribut"
11
+ value: "data"
12
+ condition: "kondisi"
13
+ sort: "urutan"
14
+ asc: "ascending"
15
+ desc: "descending"
16
+ predicates:
17
+ eq: "sama dengan"
18
+ eq_any: "sama beberapa dengan"
19
+ eq_all: "sama seluruhnya dengan"
20
+ not_eq: "tidak sama dengan"
21
+ not_eq_any: "tidak sama beberapa dengan"
22
+ not_eq_all: "tidak semua seluruhnya dengan"
23
+ matches: "mirip"
24
+ matches_any: "mirip beberapa dengan"
25
+ matches_all: "mirip semua dengan"
26
+ does_not_match: "tidak mirip dengan"
27
+ does_not_match_any: "tidak mirip beberapa dengan"
28
+ does_not_match_all: "tidak mirip semua dengan"
29
+ lt: "kurang dari"
30
+ lt_any: "kurang beberapa dengan"
31
+ lt_all: "kurang seluruhnya dengan"
32
+ lteq: "kurang lebih"
33
+ lteq_any: "kurang lebih beberapa dengan"
34
+ lteq_all: "kurang lebih semua dengan"
35
+ gt: "lebih besar daripada"
36
+ gt_any: "lebih besar beberapa dengan"
37
+ gt_all: "lebih besar semua dengan"
38
+ gteq: "lebih besar atau sama dengan"
39
+ gteq_any: "beberapa lebih besar atau sama dengan"
40
+ gteq_all: "semua lebih besar atau sama dengan"
41
+ in: "di"
42
+ in_any: "di beberapa"
43
+ in_all: "di semua"
44
+ not_in: "tidak di"
45
+ not_in_any: "tidak di beberapa"
46
+ not_in_all: "tidak semua di"
47
+ cont: "mengandung"
48
+ cont_any: "mengandung beberapa"
49
+ cont_all: "mengandung semua"
50
+ not_cont: "tidak mengandung"
51
+ not_cont_any: "tidak mengandung beberapa"
52
+ not_cont_all: "tidak mengandung semua"
53
+ start: "diawali dengan"
54
+ start_any: "diawali beberapa dengan"
55
+ start_all: "diawali semua dengan"
56
+ not_start: "tidak diawali dengan"
57
+ not_start_any: "tidak diawali beberapa dengan"
58
+ not_start_all: "tidak diawali semua dengan"
59
+ end: "diakhiri dengan"
60
+ end_any: "diakhiri beberapa dengan"
61
+ end_all: "diakhiri semua dengan"
62
+ not_end: "tidak diakhiri dengan"
63
+ not_end_any: "tidak diakhiri dengan beberapa"
64
+ not_end_all: "tidak diakhiri dengan semua"
65
+ 'true': "bernilai benar"
66
+ 'false': "bernilai salah"
67
+ present: "ada"
68
+ blank: "kosong"
69
+ 'null': "null"
70
+ not_null: "tidak null"
@@ -0,0 +1,70 @@
1
+ ja:
2
+ ransack:
3
+ search: "検索"
4
+ predicate: "は以下である"
5
+ and: "と"
6
+ or: "あるいは"
7
+ any: "いずれか"
8
+ all: "全て"
9
+ combinator: "組み合わせ"
10
+ attribute: "属性"
11
+ value: "値"
12
+ condition: "状態"
13
+ sort: "分類"
14
+ asc: "昇順"
15
+ desc: "降順"
16
+ predicates:
17
+ eq: "は以下と等しい"
18
+ eq_any: "は以下のいずれかに等しい"
19
+ eq_all: "は以下の全てに等しい"
20
+ not_eq: "は以下と等しくない"
21
+ not_eq_any: "は以下のいずれかに等しくない"
22
+ not_eq_all: "は以下の全てと等しくない"
23
+ matches: "は以下と合致している"
24
+ matches_any: "は以下のいずれかと合致している"
25
+ matches_all: "は以下の全てと合致している"
26
+ does_not_match: "は以下と合致していない"
27
+ does_not_match_any: "は以下のいずれかに合致していない"
28
+ does_not_match_all: "は以下の全てに合致していない"
29
+ lt: "は以下よりも小さい"
30
+ lt_any: "は以下のいずれかより小さい"
31
+ lt_all: "は以下の全てよりも小さい"
32
+ lteq: "は以下より小さいか等しい"
33
+ lteq_any: "は以下のいずれかより小さいか等しい"
34
+ lteq_all: "は以下の全てより小さいか等しい"
35
+ gt: "は以下より大きい"
36
+ gt_any: "は以下のいずれかより大きい"
37
+ gt_all: "は以下の全てより大きい"
38
+ gteq: "は以下より大きいか等しい"
39
+ gteq_any: "は以下のいずれかより大きいか等しい"
40
+ gteq_all: "は以下の全てより大きいか等しい"
41
+ in: "は以下の範囲内である"
42
+ in_any: "は以下のいずれかの範囲内である"
43
+ in_all: "は以下の全ての範囲内である"
44
+ not_in: "は以下の範囲内でない"
45
+ not_in_any: "は以下のいずれかの範囲内でない"
46
+ not_in_all: "は以下の全ての範囲内"
47
+ cont: "は以下を含む"
48
+ cont_any: "はいずれかを含む"
49
+ cont_all: "は以下の全てを含む"
50
+ not_cont: "は含まない"
51
+ not_cont_any: "は以下のいずれかを含まない"
52
+ not_cont_all: "は以下の全てを含まない"
53
+ start: "は以下で始まる"
54
+ start_any: "は以下のどれかで始まる"
55
+ start_all: "は以下の全てで始まる"
56
+ not_start: "は以下で始まらない"
57
+ not_start_any: "は以下のいずれかで始まらない"
58
+ not_start_all: "は以下の全てで始まらない"
59
+ end: "は以下で終わる"
60
+ end_any: "は以下のいずれかで終わる"
61
+ end_all: "は以下の全てで終わる"
62
+ not_end: "は以下のどれでも終わらない"
63
+ not_end_any: "は以下のいずれかで終わらない"
64
+ not_end_all: "は以下の全てで終わらない"
65
+ 'true': "真"
66
+ 'false': "偽"
67
+ present: "は存在する"
68
+ blank: "は空である"
69
+ 'null': "無効"
70
+ not_null: "は無効ではない"
@@ -0,0 +1,70 @@
1
+ pt-BR:
2
+ ransack:
3
+ search: "pesquisar"
4
+ predicate: "predicado"
5
+ and: "e"
6
+ or: "ou"
7
+ any: "algum"
8
+ all: "todos"
9
+ combinator: "combinador"
10
+ attribute: "atributo"
11
+ value: "valor"
12
+ condition: "condição"
13
+ sort: "classificar"
14
+ asc: "ascendente"
15
+ desc: "descendente"
16
+ predicates:
17
+ eq: "igual"
18
+ eq_any: "igual a algum"
19
+ eq_all: "igual a todos"
20
+ not_eq: "não é igual a"
21
+ not_eq_any: "não é igual a algum"
22
+ not_eq_all: "não é igual a todos"
23
+ matches: "corresponde"
24
+ matches_any: "corresponde a algum"
25
+ matches_all: "corresponde a todos"
26
+ does_not_match: "não corresponde"
27
+ does_not_match_any: "não corresponde a algum"
28
+ does_not_match_all: "não corresponde a todos"
29
+ lt: "menor que"
30
+ lt_any: "menor que algum"
31
+ lt_all: "menor que todos"
32
+ lteq: "menor ou igual a"
33
+ lteq_any: "menor ou igual a algum"
34
+ lteq_all: "menor ou igual a todos"
35
+ gt: "maior que"
36
+ gt_any: "maior que algum"
37
+ gt_all: "maior que todos"
38
+ gteq: "maior que ou igual a"
39
+ gteq_any: "maior que ou igual a algum"
40
+ gteq_all: "maior que ou igual a todos"
41
+ in: "em"
42
+ in_any: "em algum"
43
+ in_all: "em todos"
44
+ not_in: "não em"
45
+ not_in_any: "não em algum"
46
+ not_in_all: "não em todos"
47
+ cont: "contém"
48
+ cont_any: "contém algum"
49
+ cont_all: "contém todos"
50
+ not_cont: "não contém"
51
+ not_cont_any: "não contém algum"
52
+ not_cont_all: "não contém todos"
53
+ start: "começa com"
54
+ start_any: "começa com algum"
55
+ start_all: "começa com todos"
56
+ not_start: "não começa com"
57
+ not_start_any: "não começa com algum"
58
+ not_start_all: "não começa com algum"
59
+ end: "termina com"
60
+ end_any: "termina com algum"
61
+ end_all: "termina com todos"
62
+ not_end: "não termina com"
63
+ not_end_any: "não termina com algum"
64
+ not_end_all: "não termina com todos"
65
+ 'true': "é verdadeiro"
66
+ 'false': "é falso"
67
+ present: "está presente"
68
+ blank: "está em branco"
69
+ 'null': "é nulo"
70
+ not_null: "não é nulo"
@@ -1,4 +1,4 @@
1
- zh:
1
+ zh-CN:
2
2
  ransack:
3
3
  search: "搜索"
4
4
  predicate: "基于(predicate)"
@@ -0,0 +1,70 @@
1
+ zh-TW:
2
+ ransack:
3
+ search: "搜尋"
4
+ predicate: "基於"
5
+ and: "而且"
6
+ or: "或者"
7
+ any: "任何"
8
+ all: "所有"
9
+ combinator: "條件組合"
10
+ attribute: "屬性"
11
+ value: "數值"
12
+ condition: "條件"
13
+ sort: "排序"
14
+ asc: "升冪排序"
15
+ desc: "降冪排序"
16
+ predicates:
17
+ eq: "等於"
18
+ eq_any: "等於任何一個值"
19
+ eq_all: "等於所有值"
20
+ not_eq: "不等於"
21
+ not_eq_any: "不等於任何一個值"
22
+ not_eq_all: "不等於所有值"
23
+ matches: "符合"
24
+ matches_any: "符合任何一個條件"
25
+ matches_all: "符合所有條件"
26
+ does_not_match: "不符合"
27
+ does_not_match_any: "不符合任何一個條件"
28
+ does_not_match_all: "不符合所有條件"
29
+ lt: "小於"
30
+ lt_any: "小於任何一個值"
31
+ lt_all: "小於所有值"
32
+ lteq: "小於或等於"
33
+ lteq_any: "小於或等於任何一個值"
34
+ lteq_all: "小於或等於所有值"
35
+ gt: "大於"
36
+ gt_any: "大於任何一個值"
37
+ gt_all: "大於所有值"
38
+ gteq: "大於或等於"
39
+ gteq_any: "大於或等於任何一個值"
40
+ gteq_all: "大於或等於所有值"
41
+ in: "被包含於"
42
+ in_any: "被包含於任何一個值"
43
+ in_all: "被包含於所有值"
44
+ not_in: "不被包含於"
45
+ not_in_any: "不被包含於任何一個值"
46
+ not_in_all: "不被包含於所有值"
47
+ cont: "包含"
48
+ cont_any: "包含任何一個值"
49
+ cont_all: "包含所有值"
50
+ not_cont: "不包含"
51
+ not_cont_any: "不包含任何一個值"
52
+ not_cont_all: "不包含所有值"
53
+ start: "以某個值開始"
54
+ start_any: "以任何一個值開始"
55
+ start_all: "以所有值開始"
56
+ not_start: "不以某個值開始"
57
+ not_start_any: "不以任何一值開始"
58
+ not_start_all: "不以所有值開始"
59
+ end: "以某個值結尾"
60
+ end_any: "以任何一個值結尾"
61
+ end_all: "以所有值結尾"
62
+ not_end: "不以某個值結尾"
63
+ not_end_any: "不以任何一個值結尾"
64
+ not_end_all: "不以所有值結尾"
65
+ 'true': "為真"
66
+ 'false': "為假"
67
+ present: "有值"
68
+ blank: "為空"
69
+ 'null': "為 null"
70
+ not_null: "不為 null"
@@ -3,6 +3,6 @@ require 'ransack/nodes/node'
3
3
  require 'ransack/nodes/attribute'
4
4
  require 'ransack/nodes/value'
5
5
  require 'ransack/nodes/condition'
6
- Ransack::Adapters.require_nodes
6
+ Ransack::Adapters.object_mapper.require_nodes
7
7
  require 'ransack/nodes/sort'
8
8
  require 'ransack/nodes/grouping'
@@ -16,7 +16,6 @@ module Ransack
16
16
 
17
17
  def name=(name)
18
18
  @name = name
19
- context.bind(self, name) unless name.blank?
20
19
  end
21
20
 
22
21
  def valid?
@@ -25,6 +24,10 @@ module Ransack
25
24
  .include?(attr_name.split('.').last)
26
25
  end
27
26
 
27
+ def associated_collection?
28
+ parent.respond_to?(:reflection) && parent.reflection.collection?
29
+ end
30
+
28
31
  def type
29
32
  if ransacker
30
33
  return ransacker.type
@@ -27,14 +27,26 @@ module Ransack
27
27
 
28
28
  private
29
29
 
30
- def get_arel_attribute
31
- if ransacker
32
- ransacker.attr_from(self)
33
- else
34
- context.table_for(parent)[attr_name]
35
- end
30
+ def get_arel_attribute
31
+ if ransacker
32
+ ransacker.attr_from(self)
33
+ else
34
+ get_attribute
36
35
  end
36
+ end
37
37
 
38
+ def get_attribute
39
+ if is_alias_attribute?
40
+ context.table_for(parent)[parent.base_klass.attribute_aliases[attr_name]]
41
+ else
42
+ context.table_for(parent)[attr_name]
43
+ end
44
+ end
45
+
46
+ def is_alias_attribute?
47
+ Ransack::SUPPORTS_ATTRIBUTE_ALIAS &&
48
+ parent.base_klass.attribute_aliases.key?(attr_name)
49
+ end
38
50
  end
39
51
  end
40
52
  end
@@ -9,9 +9,10 @@ module Ransack
9
9
 
10
10
  class << self
11
11
  def extract(context, key, values)
12
- attributes, predicate = extract_attributes_and_predicate(key, context)
12
+ attributes, predicate, combinator =
13
+ extract_values_for_condition(key, context)
14
+
13
15
  if attributes.size > 0 && predicate
14
- combinator = key.match(/_(or|and)_/) ? $1 : nil
15
16
  condition = self.new(context)
16
17
  condition.build(
17
18
  :a => attributes,
@@ -31,20 +32,34 @@ module Ransack
31
32
 
32
33
  private
33
34
 
34
- def extract_attributes_and_predicate(key, context = nil)
35
- str = key.dup
36
- name = Predicate.detect_and_strip_from_string!(str)
37
- predicate = Predicate.named(name)
38
- unless predicate || Ransack.options[:ignore_unknown_conditions]
39
- raise ArgumentError, "No valid predicate for #{key}"
40
- end
41
- if context.present? && context.attribute_method?(str)
42
- attributes = [str]
43
- else
44
- attributes = str.split(/_and_|_or_/)
35
+ def extract_values_for_condition(key, context = nil)
36
+ str = key.dup
37
+ name = Predicate.detect_and_strip_from_string!(str)
38
+ predicate = Predicate.named(name)
39
+
40
+ unless predicate || Ransack.options[:ignore_unknown_conditions]
41
+ raise ArgumentError, "No valid predicate for #{key}"
42
+ end
43
+
44
+ if context.present?
45
+ str = context.ransackable_alias(str)
46
+ end
47
+
48
+ combinator =
49
+ if str.match(/_(or|and)_/)
50
+ $1
51
+ else
52
+ nil
53
+ end
54
+
55
+ if context.present? && context.attribute_method?(str)
56
+ attributes = [str]
57
+ else
58
+ attributes = str.split(/_and_|_or_/)
59
+ end
60
+
61
+ [attributes, predicate, combinator]
45
62
  end
46
- [attributes, predicate]
47
- end
48
63
  end
49
64
 
50
65
  def valid?
@@ -64,14 +79,12 @@ module Ransack
64
79
  def attributes=(args)
65
80
  case args
66
81
  when Array
67
- args.each do |attr|
68
- attr = Attribute.new(@context, attr)
69
- self.attributes << attr if attr.valid?
82
+ args.each do |name|
83
+ build_attribute(name)
70
84
  end
71
85
  when Hash
72
86
  args.each do |index, attrs|
73
- attr = Attribute.new(@context, attrs[:name], attrs[:ransacker_args])
74
- self.attributes << attr if attr.valid?
87
+ build_attribute(attrs[:name], attrs[:ransacker_args])
75
88
  end
76
89
  else
77
90
  raise ArgumentError,
@@ -114,9 +127,13 @@ module Ransack
114
127
  alias :m= :combinator=
115
128
  alias :m :combinator
116
129
 
117
- def build_attribute(name = nil)
118
- Attribute.new(@context, name).tap do |attribute|
119
- self.attributes << attribute
130
+ def build_attribute(name = nil, ransacker_args = [])
131
+ Attribute.new(@context, name, ransacker_args).tap do |attribute|
132
+ @context.bind(attribute, attribute.name)
133
+ self.attributes << attribute if attribute.valid?
134
+ if predicate && !negative?
135
+ @context.lock_association(attribute.parent)
136
+ end
120
137
  end
121
138
  end
122
139
 
@@ -168,6 +185,10 @@ module Ransack
168
185
 
169
186
  def predicate_name=(name)
170
187
  self.predicate = Predicate.named(name)
188
+ unless negative?
189
+ attributes.each { |a| context.lock_association(a.parent) }
190
+ end
191
+ @predicate
171
192
  end
172
193
  alias :p= :predicate_name=
173
194
 
@@ -196,15 +217,20 @@ module Ransack
196
217
  val = predicate.format(val)
197
218
  val
198
219
  end
199
- predicate.wants_array ? formatted : formatted.first
220
+ if predicate.wants_array
221
+ formatted
222
+ else
223
+ formatted.first
224
+ end
200
225
  end
201
226
 
202
227
  def arel_predicate_for_attribute(attr)
203
228
  if predicate.arel_predicate === Proc
204
229
  values = casted_values_for_attribute(attr)
205
- predicate.arel_predicate.call(
206
- predicate.wants_array ? values : values.first
207
- )
230
+ unless predicate.wants_array
231
+ values = values.first
232
+ end
233
+ predicate.arel_predicate.call(values)
208
234
  else
209
235
  predicate.arel_predicate
210
236
  end
@@ -224,10 +250,14 @@ module Ransack
224
250
  ]
225
251
  .reject { |e| e[1].blank? }
226
252
  .map { |v| "#{v[0]}: #{v[1]}" }
227
- .join(Constants::COMMA_SPACE)
253
+ .join(', '.freeze)
228
254
  "Condition <#{data}>"
229
255
  end
230
256
 
257
+ def negative?
258
+ predicate.negative?
259
+ end
260
+
231
261
  private
232
262
 
233
263
  def valid_combinator?