ransack 1.5.1 → 1.6.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.
- 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
|
|