ransack 1.5.1 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +47 -3
- data/CHANGELOG.md +106 -18
- data/CONTRIBUTING.md +56 -23
- data/Gemfile +16 -5
- data/README.md +114 -38
- data/Rakefile +30 -2
- data/lib/ransack.rb +9 -0
- data/lib/ransack/adapters/active_record/3.0/compat.rb +11 -8
- data/lib/ransack/adapters/active_record/3.0/context.rb +14 -22
- data/lib/ransack/adapters/active_record/3.1/context.rb +14 -22
- data/lib/ransack/adapters/active_record/context.rb +36 -31
- data/lib/ransack/adapters/active_record/ransack/constants.rb +113 -0
- data/lib/ransack/adapters/active_record/ransack/context.rb +64 -0
- data/lib/ransack/adapters/active_record/ransack/nodes/condition.rb +48 -0
- data/lib/ransack/adapters/active_record/ransack/translate.rb +12 -0
- data/lib/ransack/adapters/active_record/ransack/visitor.rb +24 -0
- data/lib/ransack/adapters/mongoid.rb +13 -0
- data/lib/ransack/adapters/mongoid/3.2/.gitkeep +0 -0
- data/lib/ransack/adapters/mongoid/attributes/attribute.rb +37 -0
- data/lib/ransack/adapters/mongoid/attributes/order_predications.rb +17 -0
- data/lib/ransack/adapters/mongoid/attributes/predications.rb +141 -0
- data/lib/ransack/adapters/mongoid/base.rb +126 -0
- data/lib/ransack/adapters/mongoid/context.rb +208 -0
- data/lib/ransack/adapters/mongoid/inquiry_hash.rb +23 -0
- data/lib/ransack/adapters/mongoid/ransack/constants.rb +88 -0
- data/lib/ransack/adapters/mongoid/ransack/context.rb +60 -0
- data/lib/ransack/adapters/mongoid/ransack/nodes/condition.rb +27 -0
- data/lib/ransack/adapters/mongoid/ransack/translate.rb +13 -0
- data/lib/ransack/adapters/mongoid/ransack/visitor.rb +24 -0
- data/lib/ransack/adapters/mongoid/table.rb +35 -0
- data/lib/ransack/configuration.rb +22 -4
- data/lib/ransack/constants.rb +26 -120
- data/lib/ransack/context.rb +32 -60
- data/lib/ransack/helpers/form_builder.rb +50 -36
- data/lib/ransack/helpers/form_helper.rb +148 -104
- data/lib/ransack/naming.rb +11 -11
- data/lib/ransack/nodes.rb +2 -0
- data/lib/ransack/nodes/bindable.rb +12 -4
- data/lib/ransack/nodes/condition.rb +5 -22
- data/lib/ransack/nodes/grouping.rb +9 -10
- data/lib/ransack/nodes/sort.rb +3 -2
- data/lib/ransack/nodes/value.rb +1 -2
- data/lib/ransack/predicate.rb +3 -3
- data/lib/ransack/search.rb +46 -13
- data/lib/ransack/translate.rb +8 -8
- data/lib/ransack/version.rb +1 -1
- data/lib/ransack/visitor.rb +4 -16
- data/ransack.gemspec +1 -0
- data/spec/mongoid/adapters/mongoid/base_spec.rb +276 -0
- data/spec/mongoid/adapters/mongoid/context_spec.rb +56 -0
- data/spec/mongoid/configuration_spec.rb +66 -0
- data/spec/mongoid/dependencies_spec.rb +8 -0
- data/spec/mongoid/helpers/ransack_helper.rb +11 -0
- data/spec/mongoid/nodes/condition_spec.rb +34 -0
- data/spec/mongoid/nodes/grouping_spec.rb +13 -0
- data/spec/mongoid/predicate_spec.rb +155 -0
- data/spec/mongoid/search_spec.rb +446 -0
- data/spec/mongoid/support/mongoid.yml +6 -0
- data/spec/mongoid/support/schema.rb +128 -0
- data/spec/mongoid/translate_spec.rb +14 -0
- data/spec/mongoid_spec_helper.rb +59 -0
- data/spec/ransack/adapters/active_record/base_spec.rb +68 -35
- data/spec/ransack/dependencies_spec.rb +3 -1
- data/spec/ransack/helpers/form_builder_spec.rb +6 -6
- data/spec/ransack/helpers/form_helper_spec.rb +114 -47
- data/spec/ransack/nodes/condition_spec.rb +2 -2
- data/spec/ransack/search_spec.rb +2 -6
- data/spec/ransack/translate_spec.rb +1 -1
- data/spec/spec_helper.rb +2 -3
- data/spec/support/schema.rb +9 -0
- metadata +49 -4
@@ -0,0 +1,35 @@
|
|
1
|
+
module Ransack
|
2
|
+
module Adapters
|
3
|
+
module Mongoid
|
4
|
+
class Table
|
5
|
+
attr_accessor :name
|
6
|
+
|
7
|
+
alias :table_name :name
|
8
|
+
|
9
|
+
def initialize(object, engine = nil)
|
10
|
+
@object = object
|
11
|
+
@name = object.collection.name
|
12
|
+
@engine = engine
|
13
|
+
@columns = nil
|
14
|
+
@aliases = []
|
15
|
+
@table_alias = nil
|
16
|
+
@primary_key = nil
|
17
|
+
|
18
|
+
if Hash === engine
|
19
|
+
# @engine = engine[:engine] || Table.engine
|
20
|
+
|
21
|
+
# Sometime AR sends an :as parameter to table, to let the table know
|
22
|
+
# that it is an Alias. We may want to override new, and return a
|
23
|
+
# TableAlias node?
|
24
|
+
# @table_alias = engine[:as] unless engine[:as].to_s == @name
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def [](name)
|
29
|
+
Ransack::Adapters::Mongoid::Attribute.new self, name
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -24,7 +24,7 @@ module Ransack
|
|
24
24
|
|
25
25
|
self.predicates[name] = Predicate.new(opts)
|
26
26
|
|
27
|
-
|
27
|
+
Constants::SUFFIXES.each do |suffix|
|
28
28
|
compound_name = name + suffix
|
29
29
|
self.predicates[compound_name] = Predicate.new(
|
30
30
|
opts.merge(
|
@@ -38,13 +38,31 @@ module Ransack
|
|
38
38
|
end if compounds
|
39
39
|
end
|
40
40
|
|
41
|
-
# default search_key
|
41
|
+
# The default `search_key` name is `:q`. The default key may be overridden
|
42
|
+
# in an initializer file like `config/initializers/ransack.rb` as follows:
|
43
|
+
#
|
44
|
+
# Ransack.configure do |config|
|
45
|
+
# # Name the search_key `:query` instead of the default `:q`
|
46
|
+
# config.search_key = :query
|
47
|
+
# end
|
48
|
+
#
|
49
|
+
# Sometimes there are situations when the default search parameter name
|
50
|
+
# cannot be used, for instance if there were two searches on one page.
|
51
|
+
# Another name can be set using the `search_key` option with Ransack
|
52
|
+
# `ransack`, `search` and `@search_form_for` methods in controllers & views.
|
53
|
+
#
|
54
|
+
# In the controller:
|
55
|
+
# @search = Log.ransack(params[:log_search], search_key: :log_search)
|
56
|
+
#
|
57
|
+
# In the view:
|
58
|
+
# <%= f.search_form_for @search, as: :log_search %>
|
59
|
+
#
|
42
60
|
def search_key=(name)
|
43
61
|
self.options[:search_key] = name
|
44
62
|
end
|
45
63
|
|
46
|
-
#
|
47
|
-
# into a search
|
64
|
+
# Raise an error if an unknown predicate, condition or attribute is passed
|
65
|
+
# into a search.
|
48
66
|
def ignore_unknown_conditions=(boolean)
|
49
67
|
self.options[:ignore_unknown_conditions] = boolean
|
50
68
|
end
|
data/lib/ransack/constants.rb
CHANGED
@@ -2,22 +2,39 @@ module Ransack
|
|
2
2
|
module Constants
|
3
3
|
ASC = 'asc'.freeze
|
4
4
|
DESC = 'desc'.freeze
|
5
|
+
ASC_DESC = [ASC, DESC].freeze
|
6
|
+
|
5
7
|
ASC_ARROW = '▲'.freeze
|
6
8
|
DESC_ARROW = '▼'.freeze
|
9
|
+
|
7
10
|
OR = 'or'.freeze
|
8
11
|
AND = 'and'.freeze
|
12
|
+
SPACED_AND = ' AND '.freeze
|
13
|
+
|
9
14
|
SORT = 'sort'.freeze
|
10
15
|
SORT_LINK = 'sort_link'.freeze
|
16
|
+
SORT_DIRECTION = 'sort_direction'.freeze
|
17
|
+
|
18
|
+
CAP_SEARCH = 'Search'.freeze
|
11
19
|
SEARCH = 'search'.freeze
|
12
|
-
|
20
|
+
SEARCHES = 'searches'.freeze
|
21
|
+
|
13
22
|
ATTRIBUTE = 'attribute'.freeze
|
14
|
-
|
23
|
+
ATTRIBUTES = 'attributes'.freeze
|
15
24
|
COMBINATOR = 'combinator'.freeze
|
25
|
+
|
16
26
|
SPACE = ' '.freeze
|
17
27
|
COMMA_SPACE = ', '.freeze
|
28
|
+
COLON_SPACE = ': '.freeze
|
29
|
+
TWO_COLONS = '::'.freeze
|
18
30
|
UNDERSCORE = '_'.freeze
|
31
|
+
LEFT_PARENTHESIS = '('.freeze
|
32
|
+
Q = 'q'.freeze
|
33
|
+
I = 'i'.freeze
|
19
34
|
NON_BREAKING_SPACE = ' '.freeze
|
35
|
+
DOT_ASTERIX = '.*'.freeze
|
20
36
|
EMPTY = ''.freeze
|
37
|
+
|
21
38
|
STRING_JOIN = 'string_join'.freeze
|
22
39
|
ASSOCIATION_JOIN = 'association_join'.freeze
|
23
40
|
STASHED_JOIN = 'stashed_join'.freeze
|
@@ -25,138 +42,27 @@ module Ransack
|
|
25
42
|
|
26
43
|
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
|
27
44
|
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
|
28
|
-
BOOLEAN_VALUES = TRUE_VALUES + FALSE_VALUES
|
45
|
+
BOOLEAN_VALUES = (TRUE_VALUES + FALSE_VALUES).freeze
|
29
46
|
|
30
47
|
S_SORTS = %w(s sorts).freeze
|
31
|
-
ASC_DESC = %w(asc desc).freeze
|
32
48
|
AND_OR = %w(and or).freeze
|
33
49
|
IN_NOT_IN = %w(in not_in).freeze
|
34
50
|
SUFFIXES = %w(_any _all).freeze
|
35
51
|
AREL_PREDICATES = %w(
|
36
52
|
eq not_eq matches does_not_match lt lteq gt gteq in not_in
|
37
53
|
).freeze
|
54
|
+
A_S_I = %w(a s i).freeze
|
38
55
|
|
39
56
|
EQ = 'eq'.freeze
|
40
57
|
NOT_EQ = 'not_eq'.freeze
|
41
58
|
EQ_ANY = 'eq_any'.freeze
|
42
59
|
NOT_EQ_ALL = 'not_eq_all'.freeze
|
60
|
+
CONT = 'cont'.freeze
|
43
61
|
|
44
|
-
|
45
|
-
['cont'.freeze, {
|
46
|
-
:arel_predicate => 'matches'.freeze,
|
47
|
-
:formatter => proc { |v| "%#{escape_wildcards(v)}%" }
|
48
|
-
}
|
49
|
-
],
|
50
|
-
['i_cont'.freeze, {
|
51
|
-
:arel_predicate => 'i_matches'.freeze,
|
52
|
-
:formatter => proc { |v| "%#{escape_wildcards(v)}%" }
|
53
|
-
}
|
54
|
-
],
|
55
|
-
['not_cont'.freeze, {
|
56
|
-
:arel_predicate => 'does_not_match'.freeze,
|
57
|
-
:formatter => proc { |v| "%#{escape_wildcards(v)}%" }
|
58
|
-
}
|
59
|
-
],
|
60
|
-
['i_not_cont'.freeze, {
|
61
|
-
:arel_predicate => 'i_does_not_match'.freeze,
|
62
|
-
:formatter => proc { |v| "%#{escape_wildcards(v)}%" }
|
63
|
-
}
|
64
|
-
],
|
65
|
-
['start'.freeze, {
|
66
|
-
:arel_predicate => 'matches'.freeze,
|
67
|
-
:formatter => proc { |v| "#{escape_wildcards(v)}%" }
|
68
|
-
}
|
69
|
-
],
|
70
|
-
['not_start'.freeze, {
|
71
|
-
:arel_predicate => 'does_not_match'.freeze,
|
72
|
-
:formatter => proc { |v| "#{escape_wildcards(v)}%" }
|
73
|
-
}
|
74
|
-
],
|
75
|
-
['end'.freeze, {
|
76
|
-
:arel_predicate => 'matches'.freeze,
|
77
|
-
:formatter => proc { |v| "%#{escape_wildcards(v)}" }
|
78
|
-
}
|
79
|
-
],
|
80
|
-
['not_end'.freeze, {
|
81
|
-
:arel_predicate => 'does_not_match'.freeze,
|
82
|
-
:formatter => proc { |v| "%#{escape_wildcards(v)}" }
|
83
|
-
}
|
84
|
-
],
|
85
|
-
['true'.freeze, {
|
86
|
-
:arel_predicate => proc { |v| v ? EQ : NOT_EQ },
|
87
|
-
:compounds => false,
|
88
|
-
:type => :boolean,
|
89
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
90
|
-
:formatter => proc { |v| true }
|
91
|
-
}
|
92
|
-
],
|
93
|
-
['not_true'.freeze, {
|
94
|
-
:arel_predicate => proc { |v| v ? NOT_EQ : EQ },
|
95
|
-
:compounds => false,
|
96
|
-
:type => :boolean,
|
97
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
98
|
-
:formatter => proc { |v| true }
|
99
|
-
}
|
100
|
-
],
|
101
|
-
['false'.freeze, {
|
102
|
-
:arel_predicate => proc { |v| v ? EQ : NOT_EQ },
|
103
|
-
:compounds => false,
|
104
|
-
:type => :boolean,
|
105
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
106
|
-
:formatter => proc { |v| false }
|
107
|
-
}
|
108
|
-
],
|
109
|
-
['not_false'.freeze, {
|
110
|
-
:arel_predicate => proc { |v| v ? NOT_EQ : EQ },
|
111
|
-
:compounds => false,
|
112
|
-
:type => :boolean,
|
113
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
114
|
-
:formatter => proc { |v| false }
|
115
|
-
}
|
116
|
-
],
|
117
|
-
['present'.freeze, {
|
118
|
-
:arel_predicate => proc { |v| v ? NOT_EQ_ALL : EQ_ANY },
|
119
|
-
:compounds => false,
|
120
|
-
:type => :boolean,
|
121
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
122
|
-
:formatter => proc { |v| [nil, Ransack::Constants::EMPTY] }
|
123
|
-
}
|
124
|
-
],
|
125
|
-
['blank'.freeze, {
|
126
|
-
:arel_predicate => proc { |v| v ? EQ_ANY : NOT_EQ_ALL },
|
127
|
-
:compounds => false,
|
128
|
-
:type => :boolean,
|
129
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
130
|
-
:formatter => proc { |v| [nil, Ransack::Constants::EMPTY] }
|
131
|
-
}
|
132
|
-
],
|
133
|
-
['null'.freeze, {
|
134
|
-
:arel_predicate => proc { |v| v ? EQ : NOT_EQ },
|
135
|
-
:compounds => false,
|
136
|
-
:type => :boolean,
|
137
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v)},
|
138
|
-
:formatter => proc { |v| nil }
|
139
|
-
}
|
140
|
-
],
|
141
|
-
['not_null'.freeze, {
|
142
|
-
:arel_predicate => proc { |v| v ? NOT_EQ : EQ },
|
143
|
-
:compounds => false,
|
144
|
-
:type => :boolean,
|
145
|
-
:validator => proc { |v| BOOLEAN_VALUES.include?(v) },
|
146
|
-
:formatter => proc { |v| nil } }
|
147
|
-
]
|
148
|
-
].freeze
|
62
|
+
RAILS_4_1 = '4.1'.freeze
|
149
63
|
|
150
|
-
|
151
|
-
|
152
|
-
def escape_wildcards(unescaped)
|
153
|
-
case ActiveRecord::Base.connection.adapter_name
|
154
|
-
when "Mysql2".freeze, "PostgreSQL".freeze
|
155
|
-
# Necessary for PostgreSQL and MySQL
|
156
|
-
unescaped.to_s.gsub(/([\\|\%|.])/, '\\\\\\1')
|
157
|
-
else
|
158
|
-
unescaped
|
159
|
-
end
|
160
|
-
end
|
64
|
+
RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
|
65
|
+
RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
|
161
66
|
end
|
162
67
|
end
|
68
|
+
|
data/lib/ransack/context.rb
CHANGED
@@ -1,12 +1,28 @@
|
|
1
1
|
require 'ransack/visitor'
|
2
2
|
|
3
|
+
if defined?(::ActiveRecord::Base)
|
4
|
+
require 'ransack/adapters/active_record/ransack/visitor'
|
5
|
+
end
|
6
|
+
|
7
|
+
if defined?(::Mongoid)
|
8
|
+
require 'ransack/adapters/mongoid/ransack/visitor'
|
9
|
+
end
|
10
|
+
|
3
11
|
module Ransack
|
4
12
|
class Context
|
5
|
-
attr_reader :object, :klass, :base, :engine, :arel_visitor
|
13
|
+
attr_reader :search, :object, :klass, :base, :engine, :arel_visitor
|
6
14
|
attr_accessor :auth_object, :search_key
|
7
15
|
|
8
16
|
class << self
|
9
17
|
|
18
|
+
def for_class(klass, options = {})
|
19
|
+
raise "not implemented"
|
20
|
+
end
|
21
|
+
|
22
|
+
def for_object(object, options = {})
|
23
|
+
raise "not implemented"
|
24
|
+
end
|
25
|
+
|
10
26
|
def for(object, options = {})
|
11
27
|
context = Class === object ?
|
12
28
|
for_class(object, options) :
|
@@ -15,59 +31,14 @@ module Ransack
|
|
15
31
|
"Don't know what context to use for #{object}"
|
16
32
|
end
|
17
33
|
|
18
|
-
|
19
|
-
if klass < ActiveRecord::Base
|
20
|
-
Adapters::ActiveRecord::Context.new(klass, options)
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
def for_object(object, options = {})
|
25
|
-
case object
|
26
|
-
when ActiveRecord::Relation
|
27
|
-
Adapters::ActiveRecord::Context.new(object.klass, options)
|
28
|
-
end
|
29
|
-
end
|
30
|
-
|
31
|
-
end
|
34
|
+
end # << self
|
32
35
|
|
33
36
|
def initialize(object, options = {})
|
34
|
-
|
35
|
-
@klass = @object.klass
|
36
|
-
@join_dependency = join_dependency(@object)
|
37
|
-
@join_type = options[:join_type] || Polyamorous::OuterJoin
|
38
|
-
@search_key = options[:search_key] || Ransack.options[:search_key]
|
39
|
-
|
40
|
-
if ::ActiveRecord::VERSION::STRING >= "4.1".freeze
|
41
|
-
@base = @join_dependency.join_root
|
42
|
-
@engine = @base.base_klass.arel_engine
|
43
|
-
else
|
44
|
-
@base = @join_dependency.join_base
|
45
|
-
@engine = @base.arel_engine
|
46
|
-
end
|
47
|
-
|
48
|
-
@default_table = Arel::Table.new(
|
49
|
-
@base.table_name, :as => @base.aliased_table_name, :engine => @engine
|
50
|
-
)
|
51
|
-
@bind_pairs = Hash.new do |hash, key|
|
52
|
-
parent, attr_name = get_parent_and_attribute_name(key.to_s)
|
53
|
-
if parent && attr_name
|
54
|
-
hash[key] = [parent, attr_name]
|
55
|
-
end
|
56
|
-
end
|
37
|
+
raise "not implemented"
|
57
38
|
end
|
58
39
|
|
59
40
|
def klassify(obj)
|
60
|
-
|
61
|
-
obj
|
62
|
-
elsif obj.respond_to? :klass
|
63
|
-
obj.klass
|
64
|
-
elsif obj.respond_to? :active_record # Rails 3
|
65
|
-
obj.active_record
|
66
|
-
elsif obj.respond_to? :base_klass # Rails 4
|
67
|
-
obj.base_klass
|
68
|
-
else
|
69
|
-
raise ArgumentError, "Don't know how to klassify #{obj.inspect}"
|
70
|
-
end
|
41
|
+
raise "not implemented"
|
71
42
|
end
|
72
43
|
|
73
44
|
# Convert a string representing a chain of associations and an attribute
|
@@ -95,7 +66,7 @@ module Ransack
|
|
95
66
|
end
|
96
67
|
|
97
68
|
def traverse(str, base = @base)
|
98
|
-
str ||=
|
69
|
+
str ||= Constants::EMPTY
|
99
70
|
|
100
71
|
if (segments = str.split(/_/)).size > 0
|
101
72
|
remainder = []
|
@@ -103,12 +74,13 @@ module Ransack
|
|
103
74
|
while !found_assoc && segments.size > 0 do
|
104
75
|
# Strip the _of_Model_type text from the association name, but hold
|
105
76
|
# onto it in klass, for use as the next base
|
106
|
-
assoc, klass = unpolymorphize_association(
|
107
|
-
|
77
|
+
assoc, klass = unpolymorphize_association(
|
78
|
+
segments.join(Constants::UNDERSCORE)
|
79
|
+
)
|
108
80
|
if found_assoc = get_association(assoc, base)
|
109
81
|
base = traverse(
|
110
82
|
remainder.join(
|
111
|
-
|
83
|
+
Constants::UNDERSCORE), klass || found_assoc.klass
|
112
84
|
)
|
113
85
|
end
|
114
86
|
|
@@ -123,16 +95,16 @@ module Ransack
|
|
123
95
|
|
124
96
|
def association_path(str, base = @base)
|
125
97
|
base = klassify(base)
|
126
|
-
str ||=
|
98
|
+
str ||= Constants::EMPTY
|
127
99
|
path = []
|
128
100
|
segments = str.split(/_/)
|
129
101
|
association_parts = []
|
130
102
|
if (segments = str.split(/_/)).size > 0
|
131
103
|
while segments.size > 0 &&
|
132
|
-
!base.columns_hash[segments.join(
|
104
|
+
!base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
|
133
105
|
association_parts << segments.shift do
|
134
106
|
assoc, klass = unpolymorphize_association(
|
135
|
-
association_parts.join(
|
107
|
+
association_parts.join(Constants::UNDERSCORE)
|
136
108
|
)
|
137
109
|
if found_assoc = get_association(assoc, base)
|
138
110
|
path += association_parts
|
@@ -142,7 +114,7 @@ module Ransack
|
|
142
114
|
end
|
143
115
|
end
|
144
116
|
|
145
|
-
path.join(
|
117
|
+
path.join(Constants::UNDERSCORE)
|
146
118
|
end
|
147
119
|
|
148
120
|
def unpolymorphize_association(str)
|
@@ -166,15 +138,15 @@ module Ransack
|
|
166
138
|
klass.ransackable_scopes(auth_object).any? { |s| s.to_s == str }
|
167
139
|
end
|
168
140
|
|
169
|
-
def searchable_attributes(str =
|
141
|
+
def searchable_attributes(str = Constants::EMPTY)
|
170
142
|
traverse(str).ransackable_attributes(auth_object)
|
171
143
|
end
|
172
144
|
|
173
|
-
def sortable_attributes(str =
|
145
|
+
def sortable_attributes(str = Constants::EMPTY)
|
174
146
|
traverse(str).ransortable_attributes(auth_object)
|
175
147
|
end
|
176
148
|
|
177
|
-
def searchable_associations(str =
|
149
|
+
def searchable_associations(str = Constants::EMPTY)
|
178
150
|
traverse(str).ransackable_associations(auth_object)
|
179
151
|
end
|
180
152
|
end
|
@@ -1,5 +1,19 @@
|
|
1
1
|
require 'action_view'
|
2
2
|
|
3
|
+
# This patch is needed since this Rails commit:
|
4
|
+
# https://github.com/rails/rails/commit/c1a118a
|
5
|
+
#
|
6
|
+
# TODO: Find a better way to solve this.
|
7
|
+
#
|
8
|
+
module ActionView::Helpers::Tags
|
9
|
+
class Base
|
10
|
+
private
|
11
|
+
def value(object)
|
12
|
+
object.send @method_name if object # use send instead of public_send
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
3
17
|
RANSACK_FORM_BUILDER = 'RANSACK_FORM_BUILDER'.freeze
|
4
18
|
|
5
19
|
require 'simple_form' if
|
@@ -30,13 +44,12 @@ module Ransack
|
|
30
44
|
def attribute_select(options = nil, html_options = nil, action = nil)
|
31
45
|
options = options || {}
|
32
46
|
html_options = html_options || {}
|
33
|
-
action = action ||
|
47
|
+
action = action || Constants::SEARCH
|
34
48
|
default = options.delete(:default)
|
35
49
|
raise ArgumentError, formbuilder_error_message(
|
36
50
|
"#{action}_select") unless object.respond_to?(:context)
|
37
51
|
options[:include_blank] = true unless options.has_key?(:include_blank)
|
38
|
-
bases = [
|
39
|
-
association_array(options[:associations])
|
52
|
+
bases = [Constants::EMPTY] + association_array(options[:associations])
|
40
53
|
if bases.size > 1
|
41
54
|
collection = attribute_collection_for_bases(action, bases)
|
42
55
|
object.name ||= default if can_use_default?(
|
@@ -53,13 +66,15 @@ module Ransack
|
|
53
66
|
end
|
54
67
|
|
55
68
|
def sort_direction_select(options = {}, html_options = {})
|
56
|
-
|
57
|
-
|
69
|
+
unless object.respond_to?(:context)
|
70
|
+
raise ArgumentError,
|
71
|
+
formbuilder_error_message(Constants::SORT_DIRECTION)
|
72
|
+
end
|
58
73
|
template_collection_select(:dir, sort_array, options, html_options)
|
59
74
|
end
|
60
75
|
|
61
76
|
def sort_select(options = {}, html_options = {})
|
62
|
-
attribute_select(options, html_options,
|
77
|
+
attribute_select(options, html_options, Constants::SORT) +
|
63
78
|
sort_direction_select(options, html_options)
|
64
79
|
end
|
65
80
|
|
@@ -100,35 +115,35 @@ module Ransack
|
|
100
115
|
objects ||= @object.send(name)
|
101
116
|
objects = [objects] unless Array === objects
|
102
117
|
name = "#{options[:object_name] || object_name}[#{name}]"
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
options[:child_index] || nested_child_index(name)
|
107
|
-
}]", child, options, &block)
|
118
|
+
objects.inject(ActiveSupport::SafeBuffer.new) do |output, child|
|
119
|
+
output << @template.fields_for("#{name}[#{options[:child_index] ||
|
120
|
+
nested_child_index(name)}]", child, options, &block)
|
108
121
|
end
|
109
|
-
output
|
110
122
|
end
|
111
123
|
|
112
124
|
def predicate_select(options = {}, html_options = {})
|
113
125
|
options[:compounds] = true if options[:compounds].nil?
|
114
|
-
default = options.delete(:default) ||
|
126
|
+
default = options.delete(:default) || Constants::CONT
|
115
127
|
|
116
|
-
keys =
|
128
|
+
keys =
|
129
|
+
if options[:compounds]
|
130
|
+
Predicate.names
|
131
|
+
else
|
117
132
|
Predicate.names.reject { |k| k.match(/_(any|all)$/) }
|
133
|
+
end
|
118
134
|
if only = options[:only]
|
119
135
|
if only.respond_to? :call
|
120
136
|
keys = keys.select { |k| only.call(k) }
|
121
137
|
else
|
122
138
|
only = Array.wrap(only).map(&:to_s)
|
123
139
|
keys = keys.select {
|
124
|
-
|k| only.include? k.sub(/_(any|all)$/,
|
140
|
+
|k| only.include? k.sub(/_(any|all)$/, Constants::EMPTY)
|
125
141
|
}
|
126
142
|
end
|
127
143
|
end
|
128
144
|
collection = keys.map { |k| [k, Translate.predicate(k)] }
|
129
|
-
object.predicate ||= Predicate.named(default) if
|
130
|
-
default, :predicate, keys
|
131
|
-
)
|
145
|
+
object.predicate ||= Predicate.named(default) if
|
146
|
+
can_use_default?(default, :predicate, keys)
|
132
147
|
template_collection_select(:p, collection, options, html_options)
|
133
148
|
end
|
134
149
|
|
@@ -164,21 +179,21 @@ module Ransack
|
|
164
179
|
|
165
180
|
def sort_array
|
166
181
|
[
|
167
|
-
[
|
168
|
-
[
|
182
|
+
[Constants::ASC, object.translate(Constants::ASC)],
|
183
|
+
[Constants::DESC, object.translate(Constants::DESC)]
|
169
184
|
]
|
170
185
|
end
|
171
186
|
|
172
187
|
def combinator_choices
|
173
188
|
if Nodes::Condition === object
|
174
189
|
[
|
175
|
-
[
|
176
|
-
[
|
190
|
+
[Constants::OR, Translate.word(:any)],
|
191
|
+
[Constants::AND, Translate.word(:all)]
|
177
192
|
]
|
178
193
|
else
|
179
194
|
[
|
180
|
-
[
|
181
|
-
[
|
195
|
+
[Constants::AND, Translate.word(:all)],
|
196
|
+
[Constants::OR, Translate.word(:any)]
|
182
197
|
]
|
183
198
|
end
|
184
199
|
end
|
@@ -186,8 +201,7 @@ module Ransack
|
|
186
201
|
def association_array(obj, prefix = nil)
|
187
202
|
([prefix] + association_object(obj))
|
188
203
|
.compact
|
189
|
-
.
|
190
|
-
.map { |v| [prefix, v].compact.join(Ransack::Constants::UNDERSCORE) }
|
204
|
+
.flat_map { |v| [prefix, v].compact.join(Constants::UNDERSCORE) }
|
191
205
|
end
|
192
206
|
|
193
207
|
def association_object(obj)
|
@@ -207,7 +221,7 @@ module Ransack
|
|
207
221
|
when Array, Hash
|
208
222
|
association_array(value, key.to_s)
|
209
223
|
else
|
210
|
-
[key.to_s, [key, value].join(
|
224
|
+
[key.to_s, [key, value].join(Constants::UNDERSCORE)]
|
211
225
|
end
|
212
226
|
end
|
213
227
|
end
|
@@ -218,8 +232,10 @@ module Ransack
|
|
218
232
|
|
219
233
|
def get_attribute_element(action, base)
|
220
234
|
begin
|
221
|
-
[
|
222
|
-
|
235
|
+
[
|
236
|
+
Translate.association(base, :context => object.context),
|
237
|
+
collection_for_base(action, base)
|
238
|
+
]
|
223
239
|
rescue UntraversableAssociationError => e
|
224
240
|
nil
|
225
241
|
end
|
@@ -227,10 +243,10 @@ module Ransack
|
|
227
243
|
|
228
244
|
def attribute_collection_for_base(attributes, base = nil)
|
229
245
|
attributes.map do |c|
|
230
|
-
[
|
246
|
+
[
|
247
|
+
attr_from_base_and_column(base, c),
|
231
248
|
Translate.attribute(
|
232
|
-
attr_from_base_and_column(base, c),
|
233
|
-
:context => object.context
|
249
|
+
attr_from_base_and_column(base, c), :context => object.context
|
234
250
|
)
|
235
251
|
]
|
236
252
|
end
|
@@ -242,13 +258,11 @@ module Ransack
|
|
242
258
|
end
|
243
259
|
|
244
260
|
def attr_from_base_and_column(base, column)
|
245
|
-
[base, column].reject
|
246
|
-
.join(Ransack::Constants::UNDERSCORE)
|
261
|
+
[base, column].reject(&:blank?).join(Constants::UNDERSCORE)
|
247
262
|
end
|
248
263
|
|
249
264
|
def formbuilder_error_message(action)
|
250
|
-
"#{
|
251
|
-
action.sub(Ransack::Constants::SEARCH, Ransack::Constants::ATTRIBUTE)
|
265
|
+
"#{action.sub(Constants::SEARCH, Constants::ATTRIBUTE)
|
252
266
|
} must be called inside a search FormBuilder!"
|
253
267
|
end
|
254
268
|
|