mini-fast-sys 0.0.1
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 +7 -0
- data/mini-fast-sys.gemspec +12 -0
- data/ransack-4.4.1/LICENSE +20 -0
- data/ransack-4.4.1/README.md +101 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_association.rb +70 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_association_7_2.rb +55 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/join_dependency.rb +102 -0
- data/ransack-4.4.1/lib/polyamorous/activerecord/reflection.rb +11 -0
- data/ransack-4.4.1/lib/polyamorous/join.rb +70 -0
- data/ransack-4.4.1/lib/polyamorous/polyamorous.rb +27 -0
- data/ransack-4.4.1/lib/polyamorous/swapping_reflection_class.rb +11 -0
- data/ransack-4.4.1/lib/polyamorous/tree_node.rb +7 -0
- data/ransack-4.4.1/lib/ransack/active_record.rb +14 -0
- data/ransack-4.4.1/lib/ransack/adapters/active_record/base.rb +152 -0
- data/ransack-4.4.1/lib/ransack/adapters/active_record/context.rb +373 -0
- data/ransack-4.4.1/lib/ransack/configuration.rb +209 -0
- data/ransack-4.4.1/lib/ransack/constants.rb +176 -0
- data/ransack-4.4.1/lib/ransack/context.rb +190 -0
- data/ransack-4.4.1/lib/ransack/helpers/form_builder.rb +277 -0
- data/ransack-4.4.1/lib/ransack/helpers/form_helper.rb +311 -0
- data/ransack-4.4.1/lib/ransack/helpers.rb +2 -0
- data/ransack-4.4.1/lib/ransack/invalid_search_error.rb +3 -0
- data/ransack-4.4.1/lib/ransack/locale/ar.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/az.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/bg.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ca.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/cs.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/da.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/de.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/el.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/en.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/es.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/fa.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/fi.yml +71 -0
- data/ransack-4.4.1/lib/ransack/locale/fr.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/hu.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/id.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/it.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ja.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ko.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/nl.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/pt-BR.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ro.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/ru.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/sk.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/sv.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/tr.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/uk.yml +72 -0
- data/ransack-4.4.1/lib/ransack/locale/zh-CN.yml +70 -0
- data/ransack-4.4.1/lib/ransack/locale/zh-TW.yml +70 -0
- data/ransack-4.4.1/lib/ransack/naming.rb +58 -0
- data/ransack-4.4.1/lib/ransack/nodes/attribute.rb +59 -0
- data/ransack-4.4.1/lib/ransack/nodes/bindable.rb +52 -0
- data/ransack-4.4.1/lib/ransack/nodes/condition.rb +399 -0
- data/ransack-4.4.1/lib/ransack/nodes/grouping.rb +206 -0
- data/ransack-4.4.1/lib/ransack/nodes/node.rb +34 -0
- data/ransack-4.4.1/lib/ransack/nodes/sort.rb +54 -0
- data/ransack-4.4.1/lib/ransack/nodes/value.rb +115 -0
- data/ransack-4.4.1/lib/ransack/predicate.rb +75 -0
- data/ransack-4.4.1/lib/ransack/ransacker.rb +24 -0
- data/ransack-4.4.1/lib/ransack/search.rb +195 -0
- data/ransack-4.4.1/lib/ransack/translate.rb +156 -0
- data/ransack-4.4.1/lib/ransack/version.rb +3 -0
- data/ransack-4.4.1/lib/ransack/visitor.rb +87 -0
- data/ransack-4.4.1/lib/ransack.rb +33 -0
- data/ransack-4.4.1/spec/console.rb +13 -0
- data/ransack-4.4.1/spec/factories/articles.rb +7 -0
- data/ransack-4.4.1/spec/factories/comments.rb +7 -0
- data/ransack-4.4.1/spec/factories/notes.rb +13 -0
- data/ransack-4.4.1/spec/factories/people.rb +10 -0
- data/ransack-4.4.1/spec/factories/tags.rb +5 -0
- data/ransack-4.4.1/spec/helpers/polyamorous_helper.rb +13 -0
- data/ransack-4.4.1/spec/helpers/ransack_helper.rb +9 -0
- data/ransack-4.4.1/spec/polyamorous/activerecord_compatibility_spec.rb +15 -0
- data/ransack-4.4.1/spec/polyamorous/join_association_spec.rb +29 -0
- data/ransack-4.4.1/spec/polyamorous/join_dependency_spec.rb +80 -0
- data/ransack-4.4.1/spec/polyamorous/join_spec.rb +19 -0
- data/ransack-4.4.1/spec/ransack/adapters/active_record/base_spec.rb +943 -0
- data/ransack-4.4.1/spec/ransack/adapters/active_record/context_spec.rb +219 -0
- data/ransack-4.4.1/spec/ransack/configuration_spec.rb +201 -0
- data/ransack-4.4.1/spec/ransack/helpers/form_builder_spec.rb +169 -0
- data/ransack-4.4.1/spec/ransack/helpers/form_helper_spec.rb +1075 -0
- data/ransack-4.4.1/spec/ransack/invalid_search_error_spec.rb +27 -0
- data/ransack-4.4.1/spec/ransack/nodes/condition_spec.rb +333 -0
- data/ransack-4.4.1/spec/ransack/nodes/grouping_spec.rb +111 -0
- data/ransack-4.4.1/spec/ransack/nodes/value_spec.rb +126 -0
- data/ransack-4.4.1/spec/ransack/predicate_spec.rb +504 -0
- data/ransack-4.4.1/spec/ransack/ransacker_spec.rb +69 -0
- data/ransack-4.4.1/spec/ransack/search_spec.rb +821 -0
- data/ransack-4.4.1/spec/ransack/translate_spec.rb +16 -0
- data/ransack-4.4.1/spec/spec_helper.rb +52 -0
- data/ransack-4.4.1/spec/support/en.yml +18 -0
- data/ransack-4.4.1/spec/support/schema.rb +419 -0
- metadata +133 -0
|
@@ -0,0 +1,176 @@
|
|
|
1
|
+
module Ransack
|
|
2
|
+
module Constants
|
|
3
|
+
OR = 'or'.freeze
|
|
4
|
+
AND = 'and'.freeze
|
|
5
|
+
|
|
6
|
+
CAP_SEARCH = 'Search'.freeze
|
|
7
|
+
SEARCH = 'search'.freeze
|
|
8
|
+
SEARCHES = 'searches'.freeze
|
|
9
|
+
|
|
10
|
+
ATTRIBUTE = 'attribute'.freeze
|
|
11
|
+
ATTRIBUTES = 'attributes'.freeze
|
|
12
|
+
COMBINATOR = 'combinator'.freeze
|
|
13
|
+
|
|
14
|
+
TWO_COLONS = '::'.freeze
|
|
15
|
+
UNDERSCORE = '_'.freeze
|
|
16
|
+
LEFT_PARENTHESIS = '('.freeze
|
|
17
|
+
Q = 'q'.freeze
|
|
18
|
+
I = 'i'.freeze
|
|
19
|
+
DOT_ASTERIX = '.*'.freeze
|
|
20
|
+
|
|
21
|
+
STRING_JOIN = 'string_join'.freeze
|
|
22
|
+
ASSOCIATION_JOIN = 'association_join'.freeze
|
|
23
|
+
STASHED_JOIN = 'stashed_join'.freeze
|
|
24
|
+
JOIN_NODE = 'join_node'.freeze
|
|
25
|
+
|
|
26
|
+
TRUE_VALUES = [true, 1, '1', 't', 'T', 'true', 'TRUE'].to_set
|
|
27
|
+
FALSE_VALUES = [false, 0, '0', 'f', 'F', 'false', 'FALSE'].to_set
|
|
28
|
+
BOOLEAN_VALUES = (TRUE_VALUES + FALSE_VALUES).freeze
|
|
29
|
+
|
|
30
|
+
AND_OR = ['and'.freeze, 'or'.freeze].freeze
|
|
31
|
+
IN_NOT_IN = ['in'.freeze, 'not_in'.freeze].freeze
|
|
32
|
+
SUFFIXES = ['_any'.freeze, '_all'.freeze].freeze
|
|
33
|
+
AREL_PREDICATES = [
|
|
34
|
+
'eq'.freeze, 'not_eq'.freeze,
|
|
35
|
+
'matches'.freeze, 'does_not_match'.freeze,
|
|
36
|
+
'lt'.freeze, 'lteq'.freeze,
|
|
37
|
+
'gt'.freeze, 'gteq'.freeze,
|
|
38
|
+
'in'.freeze, 'not_in'.freeze
|
|
39
|
+
].freeze
|
|
40
|
+
A_S_I = ['a'.freeze, 's'.freeze, 'i'.freeze].freeze
|
|
41
|
+
|
|
42
|
+
EQ = 'eq'.freeze
|
|
43
|
+
NOT_EQ = 'not_eq'.freeze
|
|
44
|
+
EQ_ANY = 'eq_any'.freeze
|
|
45
|
+
NOT_EQ_ALL = 'not_eq_all'.freeze
|
|
46
|
+
CONT = 'cont'.freeze
|
|
47
|
+
|
|
48
|
+
RANSACK_SLASH_SEARCHES = 'ransack/searches'.freeze
|
|
49
|
+
RANSACK_SLASH_SEARCHES_SLASH_SEARCH = 'ransack/searches/search'.freeze
|
|
50
|
+
|
|
51
|
+
DISTINCT = 'DISTINCT '.freeze
|
|
52
|
+
|
|
53
|
+
DERIVED_PREDICATES = [
|
|
54
|
+
[CONT, {
|
|
55
|
+
arel_predicate: 'matches'.freeze,
|
|
56
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}%" }
|
|
57
|
+
}
|
|
58
|
+
],
|
|
59
|
+
['not_cont'.freeze, {
|
|
60
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
61
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}%" }
|
|
62
|
+
}
|
|
63
|
+
],
|
|
64
|
+
['i_cont'.freeze, {
|
|
65
|
+
arel_predicate: 'matches'.freeze,
|
|
66
|
+
formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
|
|
67
|
+
case_insensitive: true
|
|
68
|
+
}
|
|
69
|
+
],
|
|
70
|
+
['not_i_cont'.freeze, {
|
|
71
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
72
|
+
formatter: proc { |v| "%#{escape_wildcards(v.downcase)}%" },
|
|
73
|
+
case_insensitive: true
|
|
74
|
+
}
|
|
75
|
+
],
|
|
76
|
+
['start'.freeze, {
|
|
77
|
+
arel_predicate: 'matches'.freeze,
|
|
78
|
+
formatter: proc { |v| "#{escape_wildcards(v)}%" }
|
|
79
|
+
}
|
|
80
|
+
],
|
|
81
|
+
['not_start'.freeze, {
|
|
82
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
83
|
+
formatter: proc { |v| "#{escape_wildcards(v)}%" }
|
|
84
|
+
}
|
|
85
|
+
],
|
|
86
|
+
['end'.freeze, {
|
|
87
|
+
arel_predicate: 'matches'.freeze,
|
|
88
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}" }
|
|
89
|
+
}
|
|
90
|
+
],
|
|
91
|
+
['not_end'.freeze, {
|
|
92
|
+
arel_predicate: 'does_not_match'.freeze,
|
|
93
|
+
formatter: proc { |v| "%#{escape_wildcards(v)}" }
|
|
94
|
+
}
|
|
95
|
+
],
|
|
96
|
+
['true'.freeze, {
|
|
97
|
+
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
|
98
|
+
compounds: false,
|
|
99
|
+
type: :boolean,
|
|
100
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
101
|
+
formatter: proc { |v| true }
|
|
102
|
+
}
|
|
103
|
+
],
|
|
104
|
+
['not_true'.freeze, {
|
|
105
|
+
arel_predicate: proc { |v| v ? NOT_EQ : EQ },
|
|
106
|
+
compounds: false,
|
|
107
|
+
type: :boolean,
|
|
108
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
109
|
+
formatter: proc { |v| true }
|
|
110
|
+
}
|
|
111
|
+
],
|
|
112
|
+
['false'.freeze, {
|
|
113
|
+
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
|
114
|
+
compounds: false,
|
|
115
|
+
type: :boolean,
|
|
116
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
117
|
+
formatter: proc { |v| false }
|
|
118
|
+
}
|
|
119
|
+
],
|
|
120
|
+
['not_false'.freeze, {
|
|
121
|
+
arel_predicate: proc { |v| v ? NOT_EQ : EQ },
|
|
122
|
+
compounds: false,
|
|
123
|
+
type: :boolean,
|
|
124
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
125
|
+
formatter: proc { |v| false }
|
|
126
|
+
}
|
|
127
|
+
],
|
|
128
|
+
['present'.freeze, {
|
|
129
|
+
arel_predicate: proc { |v| v ? NOT_EQ_ALL : EQ_ANY },
|
|
130
|
+
compounds: false,
|
|
131
|
+
type: :boolean,
|
|
132
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
133
|
+
formatter: proc { |v| [nil, ''.freeze].freeze }
|
|
134
|
+
}
|
|
135
|
+
],
|
|
136
|
+
['blank'.freeze, {
|
|
137
|
+
arel_predicate: proc { |v| v ? EQ_ANY : NOT_EQ_ALL },
|
|
138
|
+
compounds: false,
|
|
139
|
+
type: :boolean,
|
|
140
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
141
|
+
formatter: proc { |v| [nil, ''.freeze].freeze }
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
['null'.freeze, {
|
|
145
|
+
arel_predicate: proc { |v| v ? EQ : NOT_EQ },
|
|
146
|
+
compounds: false,
|
|
147
|
+
type: :boolean,
|
|
148
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
149
|
+
formatter: proc { |v| nil }
|
|
150
|
+
}
|
|
151
|
+
],
|
|
152
|
+
['not_null'.freeze, {
|
|
153
|
+
arel_predicate: proc { |v| v ? NOT_EQ : EQ },
|
|
154
|
+
compounds: false,
|
|
155
|
+
type: :boolean,
|
|
156
|
+
validator: proc { |v| BOOLEAN_VALUES.include?(v) },
|
|
157
|
+
formatter: proc { |v| nil } }
|
|
158
|
+
]
|
|
159
|
+
].freeze
|
|
160
|
+
|
|
161
|
+
module_function
|
|
162
|
+
# replace % \ to \% \\
|
|
163
|
+
def escape_wildcards(unescaped)
|
|
164
|
+
case ActiveRecord::Base.connection.adapter_name
|
|
165
|
+
when "Mysql2".freeze
|
|
166
|
+
# Necessary for MySQL
|
|
167
|
+
unescaped.to_s.gsub(/([\\%_])/, '\\\\\\1')
|
|
168
|
+
when "PostGIS".freeze, "PostgreSQL".freeze
|
|
169
|
+
# Necessary for PostgreSQL
|
|
170
|
+
unescaped.to_s.gsub(/([\\%_.])/, '\\\\\\1')
|
|
171
|
+
else
|
|
172
|
+
unescaped
|
|
173
|
+
end
|
|
174
|
+
end
|
|
175
|
+
end
|
|
176
|
+
end
|
|
@@ -0,0 +1,190 @@
|
|
|
1
|
+
require 'ransack/visitor'
|
|
2
|
+
|
|
3
|
+
module Ransack
|
|
4
|
+
class Context
|
|
5
|
+
attr_reader :search, :object, :klass, :base, :engine, :arel_visitor
|
|
6
|
+
attr_accessor :auth_object, :search_key
|
|
7
|
+
attr_reader :arel_visitor
|
|
8
|
+
|
|
9
|
+
class << self
|
|
10
|
+
|
|
11
|
+
def for_class(klass, options = {})
|
|
12
|
+
if klass < ActiveRecord::Base
|
|
13
|
+
Adapters::ActiveRecord::Context.new(klass, options)
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def for_object(object, options = {})
|
|
18
|
+
case object
|
|
19
|
+
when ActiveRecord::Relation
|
|
20
|
+
Adapters::ActiveRecord::Context.new(object.klass, options)
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def for(object, options = {})
|
|
25
|
+
context =
|
|
26
|
+
if Class === object
|
|
27
|
+
for_class(object, options)
|
|
28
|
+
else
|
|
29
|
+
for_object(object, options)
|
|
30
|
+
end
|
|
31
|
+
context or raise ArgumentError,
|
|
32
|
+
"Don't know what context to use for #{object}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
end # << self
|
|
36
|
+
|
|
37
|
+
def initialize(object, options = {})
|
|
38
|
+
@object = relation_for(object)
|
|
39
|
+
@klass = @object.klass
|
|
40
|
+
@join_dependency = join_dependency(@object)
|
|
41
|
+
@join_type = options[:join_type] || Polyamorous::OuterJoin
|
|
42
|
+
@search_key = options[:search_key] || Ransack.options[:search_key]
|
|
43
|
+
@associations_pot = {}
|
|
44
|
+
@tables_pot = {}
|
|
45
|
+
@lock_associations = []
|
|
46
|
+
|
|
47
|
+
@base = @join_dependency.instance_variable_get(:@join_root)
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def bind_pair_for(key)
|
|
51
|
+
@bind_pairs ||= {}
|
|
52
|
+
|
|
53
|
+
@bind_pairs[key] ||= begin
|
|
54
|
+
parent, attr_name = get_parent_and_attribute_name(key.to_s)
|
|
55
|
+
[parent, attr_name] if parent && attr_name
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
def klassify(obj)
|
|
60
|
+
if Class === obj && ::ActiveRecord::Base > obj
|
|
61
|
+
obj
|
|
62
|
+
elsif obj.respond_to? :klass
|
|
63
|
+
obj.klass
|
|
64
|
+
else
|
|
65
|
+
raise ArgumentError, "Don't know how to klassify #{obj.inspect}"
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Convert a string representing a chain of associations and an attribute
|
|
70
|
+
# into the attribute itself
|
|
71
|
+
def contextualize(str)
|
|
72
|
+
parent, attr_name = bind_pair_for(str)
|
|
73
|
+
table_for(parent)[attr_name]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def chain_scope(scope, args)
|
|
77
|
+
return unless @klass.method(scope) && args != false
|
|
78
|
+
@object = if scope_arity(scope) < 1 && args == true
|
|
79
|
+
@object.public_send(scope)
|
|
80
|
+
elsif scope_arity(scope) == 1 && args.is_a?(Array)
|
|
81
|
+
# For scopes with arity 1, pass the array as a single argument instead of splatting
|
|
82
|
+
@object.public_send(scope, args)
|
|
83
|
+
else
|
|
84
|
+
@object.public_send(scope, *args)
|
|
85
|
+
end
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
def scope_arity(scope)
|
|
89
|
+
@klass.method(scope).arity
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
def bind(object, str)
|
|
93
|
+
return nil unless str
|
|
94
|
+
object.parent, object.attr_name = bind_pair_for(str)
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
def traverse(str, base = @base)
|
|
98
|
+
str ||= ''.freeze
|
|
99
|
+
segments = str.split(Constants::UNDERSCORE)
|
|
100
|
+
unless segments.empty?
|
|
101
|
+
remainder = []
|
|
102
|
+
found_assoc = nil
|
|
103
|
+
until found_assoc || segments.empty?
|
|
104
|
+
# Strip the _of_Model_type text from the association name, but hold
|
|
105
|
+
# onto it in klass, for use as the next base
|
|
106
|
+
assoc, klass = unpolymorphize_association(
|
|
107
|
+
segments.join(Constants::UNDERSCORE)
|
|
108
|
+
)
|
|
109
|
+
if found_assoc = get_association(assoc, base)
|
|
110
|
+
base = traverse(
|
|
111
|
+
remainder.join(Constants::UNDERSCORE), klass || found_assoc.klass
|
|
112
|
+
)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
remainder.unshift segments.pop
|
|
116
|
+
end
|
|
117
|
+
unless found_assoc
|
|
118
|
+
raise(UntraversableAssociationError,
|
|
119
|
+
"No association matches #{str}")
|
|
120
|
+
end
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
klassify(base)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
def association_path(str, base = @base)
|
|
127
|
+
base = klassify(base)
|
|
128
|
+
str ||= ''.freeze
|
|
129
|
+
path = []
|
|
130
|
+
segments = str.split(Constants::UNDERSCORE)
|
|
131
|
+
association_parts = []
|
|
132
|
+
unless segments.empty?
|
|
133
|
+
while !segments.empty? &&
|
|
134
|
+
!base.columns_hash[segments.join(Constants::UNDERSCORE)] &&
|
|
135
|
+
association_parts << segments.shift
|
|
136
|
+
assoc, klass = unpolymorphize_association(
|
|
137
|
+
association_parts.join(Constants::UNDERSCORE)
|
|
138
|
+
)
|
|
139
|
+
next unless found_assoc = get_association(assoc, base)
|
|
140
|
+
path += association_parts
|
|
141
|
+
association_parts = []
|
|
142
|
+
base = klassify(klass || found_assoc)
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
path.join(Constants::UNDERSCORE)
|
|
147
|
+
end
|
|
148
|
+
|
|
149
|
+
def unpolymorphize_association(str)
|
|
150
|
+
if (match = str.match(/_of_([^_]+?)_type$/))
|
|
151
|
+
[match.pre_match, Kernel.const_get(match.captures.first)]
|
|
152
|
+
else
|
|
153
|
+
[str, nil]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
def ransackable_alias(str)
|
|
158
|
+
klass._ransack_aliases.fetch(str, klass._ransack_aliases.fetch(str.to_sym, str))
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
def ransackable_attribute?(str, klass)
|
|
162
|
+
klass.ransackable_attributes(auth_object).any? { |s| s.to_sym == str.to_sym } ||
|
|
163
|
+
klass.ransortable_attributes(auth_object).any? { |s| s.to_sym == str.to_sym }
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
def ransackable_association?(str, klass)
|
|
167
|
+
klass.ransackable_associations(auth_object).any? { |s| s.to_sym == str.to_sym }
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def ransackable_scope?(str, klass)
|
|
171
|
+
klass.ransackable_scopes(auth_object).any? { |s| s.to_sym == str.to_sym }
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
def ransackable_scope_skip_sanitize_args?(str, klass)
|
|
175
|
+
klass.ransackable_scopes_skip_sanitize_args.any? { |s| s.to_sym == str.to_sym }
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
def searchable_attributes(str = ''.freeze)
|
|
179
|
+
traverse(str).ransackable_attributes(auth_object)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def sortable_attributes(str = ''.freeze)
|
|
183
|
+
traverse(str).ransortable_attributes(auth_object)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def searchable_associations(str = ''.freeze)
|
|
187
|
+
traverse(str).ransackable_associations(auth_object)
|
|
188
|
+
end
|
|
189
|
+
end
|
|
190
|
+
end
|
|
@@ -0,0 +1,277 @@
|
|
|
1
|
+
require 'action_view'
|
|
2
|
+
|
|
3
|
+
module ActionView::Helpers::Tags
|
|
4
|
+
# TODO: Find a better way to solve this issue!
|
|
5
|
+
# This patch is needed since this Rails commit:
|
|
6
|
+
# https://github.com/rails/rails/commit/c1a118a
|
|
7
|
+
class Base
|
|
8
|
+
private
|
|
9
|
+
|
|
10
|
+
def value
|
|
11
|
+
if @allow_method_names_outside_object
|
|
12
|
+
object.send @method_name if object && object.respond_to?(@method_name, true)
|
|
13
|
+
else
|
|
14
|
+
object.send @method_name if object
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
RANSACK_FORM_BUILDER = 'RANSACK_FORM_BUILDER'.freeze
|
|
21
|
+
|
|
22
|
+
require 'simple_form' if
|
|
23
|
+
(ENV[RANSACK_FORM_BUILDER] || ''.freeze).match('SimpleForm'.freeze)
|
|
24
|
+
|
|
25
|
+
module Ransack
|
|
26
|
+
module Helpers
|
|
27
|
+
class FormBuilder < (ENV[RANSACK_FORM_BUILDER].try(:constantize) ||
|
|
28
|
+
ActionView::Helpers::FormBuilder)
|
|
29
|
+
|
|
30
|
+
def label(method, *args, &block)
|
|
31
|
+
options = args.extract_options!
|
|
32
|
+
text = args.first
|
|
33
|
+
i18n = options[:i18n] || {}
|
|
34
|
+
text ||= object.translate(
|
|
35
|
+
method, i18n.reverse_merge(include_associations: true)
|
|
36
|
+
) if object.respond_to? :translate
|
|
37
|
+
super(method, text, options, &block)
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def submit(value = nil, options = {})
|
|
41
|
+
value, options = nil, value if value.is_a?(Hash)
|
|
42
|
+
value ||= Translate.word(:search).titleize
|
|
43
|
+
super(value, options)
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def attribute_select(options = nil, html_options = nil, action = nil)
|
|
47
|
+
options ||= {}
|
|
48
|
+
html_options ||= {}
|
|
49
|
+
action ||= Constants::SEARCH
|
|
50
|
+
default = options.delete(:default)
|
|
51
|
+
raise ArgumentError, formbuilder_error_message(
|
|
52
|
+
"#{action}_select") unless object.respond_to?(:context)
|
|
53
|
+
options[:include_blank] = true unless options.has_key?(:include_blank)
|
|
54
|
+
bases = [''.freeze].freeze + association_array(options[:associations])
|
|
55
|
+
if bases.size > 1
|
|
56
|
+
collection = attribute_collection_for_bases(action, bases)
|
|
57
|
+
object.name ||= default if can_use_default?(
|
|
58
|
+
default, :name, mapped_values(collection.flatten(2))
|
|
59
|
+
)
|
|
60
|
+
template_grouped_collection_select(collection, options, html_options)
|
|
61
|
+
else
|
|
62
|
+
collection = collection_for_base(action, bases.first)
|
|
63
|
+
object.name ||= default if can_use_default?(
|
|
64
|
+
default, :name, mapped_values(collection)
|
|
65
|
+
)
|
|
66
|
+
template_collection_select(:name, collection, options, html_options)
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def sort_direction_select(options = {}, html_options = {})
|
|
71
|
+
unless object.respond_to?(:context)
|
|
72
|
+
raise ArgumentError,
|
|
73
|
+
formbuilder_error_message('sort_direction'.freeze)
|
|
74
|
+
end
|
|
75
|
+
template_collection_select(:dir, sort_array, options, html_options)
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
def sort_select(options = {}, html_options = {})
|
|
79
|
+
attribute_select(options, html_options, 'sort'.freeze) +
|
|
80
|
+
sort_direction_select(options, html_options)
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def sort_fields(*args, &block)
|
|
84
|
+
search_fields(:s, args, block)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def sort_link(attribute, *args)
|
|
88
|
+
@template.sort_link @object, attribute, *args
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
def sort_url(attribute, *args)
|
|
92
|
+
@template.sort_url @object, attribute, *args
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
def condition_fields(*args, &block)
|
|
96
|
+
search_fields(:c, args, block)
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
def grouping_fields(*args, &block)
|
|
100
|
+
search_fields(:g, args, block)
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
def attribute_fields(*args, &block)
|
|
104
|
+
search_fields(:a, args, block)
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def predicate_fields(*args, &block)
|
|
108
|
+
search_fields(:p, args, block)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
def value_fields(*args, &block)
|
|
112
|
+
search_fields(:v, args, block)
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def search_fields(name, args, block)
|
|
116
|
+
args << {} unless args.last.is_a?(Hash)
|
|
117
|
+
args.last[:builder] ||= options[:builder]
|
|
118
|
+
args.last[:parent_builder] = self
|
|
119
|
+
options = args.extract_options!
|
|
120
|
+
objects = args.shift
|
|
121
|
+
objects ||= @object.send(name)
|
|
122
|
+
objects = [objects] unless Array === objects
|
|
123
|
+
name = "#{options[:object_name] || object_name}[#{name}]"
|
|
124
|
+
objects.inject(ActiveSupport::SafeBuffer.new) do |output, child|
|
|
125
|
+
output << @template.fields_for("#{name}[#{options[:child_index] ||
|
|
126
|
+
nested_child_index(name)}]", child, options, &block)
|
|
127
|
+
end
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def predicate_select(options = {}, html_options = {})
|
|
131
|
+
options[:compounds] = true if options[:compounds].nil?
|
|
132
|
+
default = options.delete(:default) || Constants::CONT
|
|
133
|
+
|
|
134
|
+
keys =
|
|
135
|
+
if options[:compounds]
|
|
136
|
+
Predicate.names
|
|
137
|
+
else
|
|
138
|
+
Predicate.names.reject { |k| k.match(/_(any|all)$/) }
|
|
139
|
+
end
|
|
140
|
+
if only = options[:only]
|
|
141
|
+
if only.respond_to? :call
|
|
142
|
+
keys = keys.select { |k| only.call(k) }
|
|
143
|
+
else
|
|
144
|
+
only = Array.wrap(only).map(&:to_s)
|
|
145
|
+
keys = keys.select {
|
|
146
|
+
|k| only.include? k.sub(/_(any|all)$/, ''.freeze)
|
|
147
|
+
}
|
|
148
|
+
end
|
|
149
|
+
end
|
|
150
|
+
collection = keys.map { |k| [k, Translate.predicate(k)] }
|
|
151
|
+
object.predicate ||= Predicate.named(default) if
|
|
152
|
+
can_use_default?(default, :predicate, keys)
|
|
153
|
+
template_collection_select(:p, collection, options, html_options)
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
def combinator_select(options = {}, html_options = {})
|
|
157
|
+
template_collection_select(
|
|
158
|
+
:m, combinator_choices, options, html_options)
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
private
|
|
162
|
+
|
|
163
|
+
def template_grouped_collection_select(collection, options, html_options)
|
|
164
|
+
@template.grouped_collection_select(
|
|
165
|
+
@object_name, :name, collection, :last, :first, :first, :last,
|
|
166
|
+
objectify_options(options), @default_options.merge(html_options)
|
|
167
|
+
)
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
def template_collection_select(name, collection, options, html_options)
|
|
171
|
+
@template.collection_select(
|
|
172
|
+
@object_name, name, collection, :first, :last,
|
|
173
|
+
objectify_options(options), @default_options.merge(html_options)
|
|
174
|
+
)
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
def can_use_default?(default, attribute, values)
|
|
178
|
+
object.respond_to?("#{attribute}=") && default &&
|
|
179
|
+
values.include?(default.to_s)
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
def mapped_values(values)
|
|
183
|
+
values.map { |v| v.is_a?(Array) ? v.first : nil }.compact
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def sort_array
|
|
187
|
+
[
|
|
188
|
+
['asc'.freeze, object.translate('asc'.freeze)].freeze,
|
|
189
|
+
['desc'.freeze, object.translate('desc'.freeze)].freeze
|
|
190
|
+
].freeze
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def combinator_choices
|
|
194
|
+
if Nodes::Condition === object
|
|
195
|
+
[
|
|
196
|
+
[Constants::OR, Translate.word(:any)],
|
|
197
|
+
[Constants::AND, Translate.word(:all)]
|
|
198
|
+
]
|
|
199
|
+
else
|
|
200
|
+
[
|
|
201
|
+
[Constants::AND, Translate.word(:all)],
|
|
202
|
+
[Constants::OR, Translate.word(:any)]
|
|
203
|
+
]
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
def association_array(obj, prefix = nil)
|
|
208
|
+
([prefix] + association_object(obj))
|
|
209
|
+
.compact
|
|
210
|
+
.flat_map { |v| [prefix, v].compact.join(Constants::UNDERSCORE) }
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
def association_object(obj)
|
|
214
|
+
case obj
|
|
215
|
+
when Array
|
|
216
|
+
obj
|
|
217
|
+
when Hash
|
|
218
|
+
association_hash(obj)
|
|
219
|
+
else
|
|
220
|
+
[obj]
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
def association_hash(obj)
|
|
225
|
+
obj.map do |key, value|
|
|
226
|
+
case value
|
|
227
|
+
when Array, Hash
|
|
228
|
+
association_array(value, key.to_s)
|
|
229
|
+
else
|
|
230
|
+
[key.to_s, [key, value].join(Constants::UNDERSCORE)]
|
|
231
|
+
end
|
|
232
|
+
end
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def attribute_collection_for_bases(action, bases)
|
|
236
|
+
bases.map { |base| get_attribute_element(action, base) }.compact
|
|
237
|
+
end
|
|
238
|
+
|
|
239
|
+
def get_attribute_element(action, base)
|
|
240
|
+
begin
|
|
241
|
+
[
|
|
242
|
+
Translate.association(base, context: object.context),
|
|
243
|
+
collection_for_base(action, base)
|
|
244
|
+
]
|
|
245
|
+
rescue UntraversableAssociationError
|
|
246
|
+
nil
|
|
247
|
+
end
|
|
248
|
+
end
|
|
249
|
+
|
|
250
|
+
def attribute_collection_for_base(attributes, base = nil)
|
|
251
|
+
attributes.map do |c|
|
|
252
|
+
[
|
|
253
|
+
attr_from_base_and_column(base, c),
|
|
254
|
+
Translate.attribute(
|
|
255
|
+
attr_from_base_and_column(base, c), context: object.context
|
|
256
|
+
)
|
|
257
|
+
]
|
|
258
|
+
end
|
|
259
|
+
end
|
|
260
|
+
|
|
261
|
+
def collection_for_base(action, base)
|
|
262
|
+
attribute_collection_for_base(
|
|
263
|
+
object.context.send("#{action}able_attributes", base), base)
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def attr_from_base_and_column(base, column)
|
|
267
|
+
[base, column].reject(&:blank?).join(Constants::UNDERSCORE)
|
|
268
|
+
end
|
|
269
|
+
|
|
270
|
+
def formbuilder_error_message(action)
|
|
271
|
+
"#{action.sub(Constants::SEARCH, Constants::ATTRIBUTE)
|
|
272
|
+
} must be called inside a search FormBuilder!"
|
|
273
|
+
end
|
|
274
|
+
|
|
275
|
+
end
|
|
276
|
+
end
|
|
277
|
+
end
|