pg_rails 7.1.5 → 7.1.6
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/pg_engine/app/controllers/admin/users_controller.rb +1 -1
- data/pg_engine/app/controllers/concerns/pg_engine/resource.rb +5 -47
- data/pg_engine/app/helpers/pg_engine/index_helper.rb +26 -30
- data/pg_engine/app/lib/pg_engine/filtros_builder.rb +78 -131
- data/pg_engine/app/policies/pg_engine/base_policy.rb +2 -2
- data/pg_engine/app/views/pg_engine/base/download.xlsx.axlsx +2 -2
- data/pg_engine/app/views/pg_engine/base/index.html.slim +2 -2
- data/pg_engine/config/initializers/ransack.rb +8 -0
- data/pg_engine/config/locales/es.yml +4 -0
- data/pg_engine/spec/controllers/concerns/pg_engine/resource_helper_spec.rb +0 -61
- data/pg_engine/spec/factories/users.rb +14 -0
- data/pg_rails/lib/pg_rails/tom_select_helpers.rb +9 -0
- data/pg_rails/lib/version.rb +1 -1
- data/pg_scaffold/lib/generators/pg_scaffold/templates/controller.rb +0 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e9ea11adc017949414ed89c42127ce6867418dcd461219fb56289a2832a938a6
|
4
|
+
data.tar.gz: 30ab308185ff7e68acebf1611161f55fa5d783bc95536db27a2026091637d69a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 61685a1f498123e153ae0a635805566b69dbf177ad079da95e53221b81c05af957cdc9d8d0de63004d48d74801cf493a7062f303c227f9cdffa08a5834442941
|
7
|
+
data.tar.gz: 6c80c211396d351891a1c4071672bae515a629d933a128cd3e9f3b5fae4d948e624b9577645cee199bd10e4d6aa55b1aafa1278e4011dc7d1e7a87a60efede3e
|
@@ -20,15 +20,10 @@ module PgEngine
|
|
20
20
|
def index
|
21
21
|
@collection = filtros_y_policy atributos_para_buscar
|
22
22
|
|
23
|
-
shared_context = Ransack::Context.
|
24
|
-
|
23
|
+
shared_context = Ransack::Adapters::ActiveRecord::Context.new(@collection)
|
25
24
|
@q = @clase_modelo.ransack(params[:q], context: shared_context)
|
26
|
-
|
27
|
-
@collection = @collection.joins(shared_context.join_sources)
|
28
|
-
vis = Ransack::Visitor.new.accept(@q.base)
|
29
|
-
@collection = @collection.where(vis)
|
25
|
+
@collection = shared_context.evaluate(@q)
|
30
26
|
|
31
|
-
@collection = sort_collection(@collection)
|
32
27
|
pg_respond_index
|
33
28
|
end
|
34
29
|
|
@@ -159,7 +154,9 @@ module PgEngine
|
|
159
154
|
def pg_respond_show(object = nil)
|
160
155
|
object ||= instancia_modelo
|
161
156
|
if params[:modal].present?
|
162
|
-
render turbo_stream: turbo_stream.append_all(
|
157
|
+
render turbo_stream: turbo_stream.append_all(
|
158
|
+
'body', partial: 'pg_layout/modal_show', locals: { object: }
|
159
|
+
)
|
163
160
|
else
|
164
161
|
respond_to do |format|
|
165
162
|
format.json { render json: object }
|
@@ -303,44 +300,5 @@ module PgEngine
|
|
303
300
|
self, clase_modelo, []
|
304
301
|
).filtrar(policy_scope(clase_modelo))
|
305
302
|
end
|
306
|
-
|
307
|
-
def do_sort(scope, field, direction)
|
308
|
-
# TODO: restringir ciertos campos?
|
309
|
-
unless scope.model.column_names.include?(field.to_s) ||
|
310
|
-
scope.model.respond_to?("order_by_#{field}")
|
311
|
-
pg_warn("No existe el campo \"#{field}\"")
|
312
|
-
return scope
|
313
|
-
end
|
314
|
-
unless direction.to_sym.in? %i[asc desc]
|
315
|
-
pg_warn("Direction not valid: \"#{direction}\"")
|
316
|
-
return scope
|
317
|
-
end
|
318
|
-
scope = if scope.model.respond_to? "order_by_#{field}"
|
319
|
-
scope.send "order_by_#{field}", direction
|
320
|
-
else
|
321
|
-
sql = scope.model.arel_table[field.to_sym].send(direction).to_sql + ' nulls last'
|
322
|
-
scope.order(sql)
|
323
|
-
end
|
324
|
-
instance_variable_set(:@field, field)
|
325
|
-
instance_variable_set(:@direction, direction)
|
326
|
-
scope
|
327
|
-
rescue ArgumentError => e
|
328
|
-
pg_warn(e)
|
329
|
-
scope
|
330
|
-
end
|
331
|
-
|
332
|
-
def sort_collection(scope, options = {})
|
333
|
-
if params[:order_by].present?
|
334
|
-
field = params[:order_by]
|
335
|
-
direction = params[:order_direction]
|
336
|
-
do_sort(scope, field, direction)
|
337
|
-
elsif options[:default].present?
|
338
|
-
field = options[:default].first[0]
|
339
|
-
direction = options[:default].first[1]
|
340
|
-
do_sort(scope, field, direction)
|
341
|
-
else
|
342
|
-
do_sort(scope, 'id', 'desc')
|
343
|
-
end
|
344
|
-
end
|
345
303
|
end
|
346
304
|
end
|
@@ -2,46 +2,42 @@
|
|
2
2
|
|
3
3
|
module PgEngine
|
4
4
|
module IndexHelper
|
5
|
-
def encabezado(
|
5
|
+
def encabezado(input, options = {})
|
6
|
+
if input.is_a? Array
|
7
|
+
campo = input.first
|
8
|
+
sort_field = input.last
|
9
|
+
else
|
10
|
+
campo = sort_field = input
|
11
|
+
end
|
12
|
+
|
6
13
|
campo = campo.to_s.sub(/_f\z/, '')
|
7
14
|
campo = campo.to_s.sub(/_text\z/, '')
|
15
|
+
sort_field = sort_field.to_s.sub(/_f\z/, '')
|
16
|
+
sort_field = sort_field.to_s.sub(/_text\z/, '')
|
17
|
+
|
8
18
|
clase = options[:clase] || @clase_modelo
|
9
19
|
key = [controller_name, action_name, 'listado_header', campo].join('.')
|
10
20
|
dflt = :"activerecord.attributes.#{clase.model_name.i18n_key}.#{campo}"
|
11
21
|
human_name = clase.human_attribute_name(key, default: dflt)
|
12
|
-
if options[:ordenable]
|
13
|
-
field = controller.instance_variable_get(:@field)
|
14
|
-
direction = controller.instance_variable_get(:@direction)
|
15
|
-
uri = URI.parse(request.url)
|
16
|
-
cgi = if uri.query.present?
|
17
|
-
CGI.parse(uri.query)
|
18
|
-
else
|
19
|
-
{}
|
20
|
-
end
|
21
|
-
cgi['order_by'] = campo
|
22
|
-
cgi['order_direction'] =
|
23
|
-
if field.to_s == campo.to_s && direction.to_s == 'desc'
|
24
|
-
'asc'
|
25
|
-
else
|
26
|
-
'desc'
|
27
|
-
end
|
28
|
-
|
29
|
-
symbol = if field.to_s == campo.to_s
|
30
|
-
if direction.to_s == 'asc'
|
31
|
-
'<i class="bi bi-sort-down-alt" />'
|
32
|
-
elsif direction.to_s == 'desc'
|
33
|
-
'<i class="bi bi-sort-up" />'
|
34
|
-
end
|
35
|
-
else
|
36
|
-
''
|
37
|
-
end
|
38
|
-
|
39
|
-
uri.query = cgi.transform_values { |b| (b.length == 1 ? b.first : b) }.to_query
|
40
22
|
|
41
|
-
|
23
|
+
if options[:ordenable]
|
24
|
+
sort_link(@q, sort_field, human_name, default_order: default_order(campo))
|
42
25
|
else
|
43
26
|
human_name
|
44
27
|
end
|
45
28
|
end
|
29
|
+
|
30
|
+
def default_order(campo)
|
31
|
+
columna = @clase_modelo.columns.find { _1.name == campo.to_s }
|
32
|
+
if columna && columna.type.to_s.include?('date')
|
33
|
+
:desc
|
34
|
+
else
|
35
|
+
:asc
|
36
|
+
end
|
37
|
+
rescue StandardError => e
|
38
|
+
pg_err e
|
39
|
+
|
40
|
+
:asc
|
41
|
+
end
|
46
42
|
end
|
47
43
|
end
|
@@ -7,13 +7,44 @@ module PgEngine
|
|
7
7
|
include PostgresHelper
|
8
8
|
attr_accessor :controller
|
9
9
|
|
10
|
-
|
10
|
+
# El orden de los sufijos es importante
|
11
|
+
SUFIJOS = %w[
|
12
|
+
desde
|
13
|
+
hasta
|
14
|
+
gteq
|
15
|
+
gt
|
16
|
+
lteq
|
17
|
+
lt
|
18
|
+
incluye
|
19
|
+
es_igual_a
|
20
|
+
in
|
21
|
+
cont_all
|
22
|
+
cont_any
|
23
|
+
not_cont
|
24
|
+
cont
|
25
|
+
eq
|
26
|
+
].freeze
|
11
27
|
|
12
28
|
def initialize(controller, clase_modelo, campos)
|
13
29
|
@clase_modelo = clase_modelo
|
14
|
-
@campos = campos
|
15
|
-
@controller = controller
|
16
30
|
@filtros = {}
|
31
|
+
@campos = campos.map do |campo|
|
32
|
+
if extraer_sufijo(campo).blank?
|
33
|
+
case tipo(campo)
|
34
|
+
when :enumerized, :boolean
|
35
|
+
:"#{campo}_eq"
|
36
|
+
when :asociacion
|
37
|
+
:"#{campo.to_s.sub(/_id$/, '')}_id_eq"
|
38
|
+
when :date, :datetime
|
39
|
+
[:"#{campo}_gteq", :"#{campo}_lteq"]
|
40
|
+
else
|
41
|
+
:"#{campo}_cont_all"
|
42
|
+
end
|
43
|
+
else
|
44
|
+
campo
|
45
|
+
end
|
46
|
+
end.flatten
|
47
|
+
@controller = controller
|
17
48
|
@campos.each { |campo| @filtros[campo] = {} }
|
18
49
|
end
|
19
50
|
|
@@ -33,96 +64,23 @@ module PgEngine
|
|
33
64
|
@filtros[campo][:scope_asociacion] = block
|
34
65
|
end
|
35
66
|
|
36
|
-
def algun_filtro_presente?
|
37
|
-
@campos.any? { |campo| parametros_controller[campo].present? }
|
38
|
-
end
|
39
|
-
|
40
67
|
def filtrar(query, parametros = nil)
|
41
68
|
parametros = parametros_controller if parametros.nil?
|
42
69
|
|
43
70
|
# Filtro soft deleted
|
44
71
|
query = query.kept if query.respond_to?(:kept) && parametros[:archived] != 'true'
|
45
72
|
|
46
|
-
@filtros.each_key do |campo|
|
47
|
-
next if parametros[campo].blank?
|
48
|
-
|
49
|
-
if @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:query].present?
|
50
|
-
query = @filtros[campo.to_sym][:query].call(query, parametros[campo])
|
51
|
-
elsif tipo(campo) == :enumerized
|
52
|
-
columna = @clase_modelo.columns.find { |c| c.name == campo.to_s }
|
53
|
-
query = if columna.array
|
54
|
-
query.where("? = any(#{@clase_modelo.table_name}.#{campo})", parametros[campo])
|
55
|
-
else
|
56
|
-
query.where("#{@clase_modelo.table_name}.#{campo} = ?", parametros[campo])
|
57
|
-
end
|
58
|
-
elsif tipo(campo).in?(%i[integer float decimal])
|
59
|
-
campo_a_comparar = "#{@clase_modelo.table_name}.#{sin_sufijo(campo)}"
|
60
|
-
query = query.where("#{campo_a_comparar} #{comparador(campo)} ?", parametros[campo])
|
61
|
-
elsif tipo(campo) == :asociacion
|
62
|
-
nombre_campo = sin_sufijo(campo)
|
63
|
-
suf = extraer_sufijo(campo)
|
64
|
-
asociacion = obtener_asociacion(nombre_campo)
|
65
|
-
if asociacion.instance_of?(ActiveRecord::Reflection::HasAndBelongsToManyReflection)
|
66
|
-
array = parametros[campo].instance_of?(Array) ? parametros[campo].join(',') : parametros[campo]
|
67
|
-
query = query.joins(nombre_campo.to_sym).group("#{@clase_modelo.table_name}.id")
|
68
|
-
.having("ARRAY_AGG(#{asociacion.join_table}.#{asociacion.association_foreign_key}) #{comparador_array(suf)} ARRAY[#{array}]::bigint[]")
|
69
|
-
elsif asociacion.instance_of?(ActiveRecord::Reflection::BelongsToReflection)
|
70
|
-
query = query.where("#{@clase_modelo.table_name}.#{campo}_id = ?", parametros[campo])
|
71
|
-
else
|
72
|
-
raise 'filtro de asociacion no soportado'
|
73
|
-
end
|
74
|
-
elsif tipo(campo).in?(%i[string text])
|
75
|
-
columna = @clase_modelo.columns.find { |c| c.name == campo.to_s }
|
76
|
-
campo_tabla = "#{@clase_modelo.table_name}.#{campo}"
|
77
|
-
match_like = "%#{parametros[campo]}%"
|
78
|
-
query =
|
79
|
-
if columna&.array
|
80
|
-
# FIXME: testear
|
81
|
-
# El CONCAT no sé para qué sirve, pero lo dejo
|
82
|
-
query.where("unaccent(CONCAT(array_to_string(#{campo_tabla}, ' '))) ILIKE unaccent(?)", I18n.transliterate(match_like).to_s)
|
83
|
-
else
|
84
|
-
match_vector = parametros[campo].split.map { |a| "#{a}:*" }.join(' & ')
|
85
|
-
condicion = "to_tsvector(coalesce(unaccent(#{campo_tabla}), '')) @@ to_tsquery( unaccent(?) )"
|
86
|
-
condicion += " OR unaccent(CONCAT(#{campo_tabla})) ILIKE unaccent(?)"
|
87
|
-
query = query.where(condicion, I18n.transliterate(match_vector).to_s,
|
88
|
-
I18n.transliterate(match_like).to_s)
|
89
|
-
end
|
90
|
-
elsif tipo(campo) == :boolean
|
91
|
-
if campo.to_s == 'discarded'
|
92
|
-
# Si el nombre del campo es 'discarded' entonces no es un campo
|
93
|
-
# real sino filtro booleano por presencia de discarded_at
|
94
|
-
case parametros[campo]
|
95
|
-
when 'si'
|
96
|
-
query = query.unscope(where: :discarded_at).where("#{@clase_modelo.table_name}.discarded_at IS NOT NULL")
|
97
|
-
when 'no'
|
98
|
-
query = query.unscope(where: :discarded_at).where("#{@clase_modelo.table_name}.discarded_at IS NULL")
|
99
|
-
end
|
100
|
-
else
|
101
|
-
# Si no simplemente hago la query por booleano
|
102
|
-
query = query.where("#{@clase_modelo.table_name}.#{campo} = ?", parametros[campo] == 'si')
|
103
|
-
end
|
104
|
-
elsif tipo(campo) == :date || tipo(campo) == :datetime
|
105
|
-
begin
|
106
|
-
fecha = Date.parse(parametros[campo])
|
107
|
-
fecha = fecha + 1.day - 1.second if tipo(campo) == :datetime && comparador(campo) == '<'
|
108
|
-
campo_a_comparar = "#{@clase_modelo.table_name}.#{sin_sufijo(campo)}"
|
109
|
-
query = query.where("#{campo_a_comparar} #{comparador(campo)} ?", fecha)
|
110
|
-
rescue ArgumentError
|
111
|
-
end
|
112
|
-
end
|
113
|
-
end
|
114
73
|
query
|
115
74
|
end
|
116
75
|
|
117
76
|
def tipo(campo)
|
118
77
|
nombre_campo = sin_sufijo(campo)
|
78
|
+
|
119
79
|
if @filtros[nombre_campo.to_sym].present? && @filtros[nombre_campo.to_sym][:tipo].present?
|
120
80
|
@filtros[nombre_campo.to_sym][:tipo]
|
121
81
|
elsif @clase_modelo.respond_to?(:enumerized_attributes) && @clase_modelo.enumerized_attributes[nombre_campo.to_s].present?
|
122
82
|
:enumerized
|
123
|
-
elsif @clase_modelo.
|
124
|
-
a.name == nombre_campo.to_sym
|
125
|
-
end.present?
|
83
|
+
elsif find_on_all_associations(@clase_modelo, campo).present?
|
126
84
|
:asociacion
|
127
85
|
else
|
128
86
|
columna = @clase_modelo.columns.find { |c| c.name == nombre_campo.to_s }
|
@@ -133,7 +91,8 @@ module PgEngine
|
|
133
91
|
# real sino filtro booleano por presencia de discarded_at
|
134
92
|
return :boolean if campo.to_s == 'discarded'
|
135
93
|
|
136
|
-
|
94
|
+
pg_warn("no existe el campo: #{nombre_campo}")
|
95
|
+
|
137
96
|
return
|
138
97
|
end
|
139
98
|
columna.type
|
@@ -165,14 +124,17 @@ module PgEngine
|
|
165
124
|
SUFIJOS.each do |sufijo|
|
166
125
|
return sufijo if campo.to_s.ends_with?("_#{sufijo}")
|
167
126
|
end
|
127
|
+
|
168
128
|
nil
|
169
129
|
end
|
170
130
|
|
171
131
|
def sin_sufijo(campo)
|
172
132
|
ret = campo.to_s.dup
|
133
|
+
|
173
134
|
SUFIJOS.each do |sufijo|
|
174
135
|
ret.gsub!(/_#{sufijo}$/, '')
|
175
136
|
end
|
137
|
+
|
176
138
|
ret
|
177
139
|
end
|
178
140
|
|
@@ -180,16 +142,21 @@ module PgEngine
|
|
180
142
|
suf = extraer_sufijo(campo)
|
181
143
|
key = [controller_name, action_name, 'filter', sin_sufijo(campo)].join('.')
|
182
144
|
dflt = :"activerecord.attributes.#{@clase_modelo.model_name.i18n_key}.#{sin_sufijo(campo)}"
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
145
|
+
human_name = @clase_modelo.human_attribute_name(key, default: dflt)
|
146
|
+
|
147
|
+
ret =
|
148
|
+
if suf.present?
|
149
|
+
"#{human_name} #{I18n.t(suf, scope: 'ransack.predicates')}"
|
150
|
+
else
|
151
|
+
human_name
|
152
|
+
end
|
153
|
+
|
154
|
+
ret.strip.downcase.tap { _1[0] = _1[0].capitalize }
|
189
155
|
end
|
190
156
|
|
191
157
|
def filtros_html(options = {})
|
192
158
|
@form = options[:form]
|
159
|
+
|
193
160
|
raise PgEngine::Error, 'se debe setear el form' if @form.blank?
|
194
161
|
|
195
162
|
res = ''
|
@@ -201,8 +168,6 @@ module PgEngine
|
|
201
168
|
end
|
202
169
|
|
203
170
|
res += case tipo(campo)
|
204
|
-
when :select_custom
|
205
|
-
filtro_select_custom(campo, placeholder_campo(campo))
|
206
171
|
when :enumerized
|
207
172
|
filtro_select(campo, placeholder_campo(campo))
|
208
173
|
when :asociacion
|
@@ -215,24 +180,30 @@ module PgEngine
|
|
215
180
|
filtro_texto(campo, placeholder_campo(campo))
|
216
181
|
end
|
217
182
|
end
|
218
|
-
|
219
|
-
|
183
|
+
|
184
|
+
if params[:q] && params[:q][:s]
|
185
|
+
res += @form.hidden_field('s', value: params[:q][:s])
|
186
|
+
end
|
187
|
+
|
220
188
|
res.html_safe
|
221
189
|
end
|
222
190
|
|
223
|
-
def
|
191
|
+
def find_on_all_associations(klass, campo)
|
224
192
|
nombre_campo = sin_sufijo(campo)
|
225
|
-
|
226
|
-
|
227
|
-
a.name == nombre_campo.to_sym
|
193
|
+
klass.reflect_on_all_associations.find do |a|
|
194
|
+
a.name == nombre_campo.to_sym || a.name == nombre_campo.sub(/_id$/, '').to_sym
|
228
195
|
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def obtener_asociacion(campo)
|
199
|
+
asociacion = find_on_all_associations(@clase_modelo, campo)
|
200
|
+
|
229
201
|
raise 'no se encontró la asociacion' if asociacion.nil?
|
230
202
|
|
231
203
|
if asociacion.instance_of?(ActiveRecord::Reflection::ThroughReflection)
|
232
204
|
through_class = asociacion.through_reflection.class_name.constantize
|
233
|
-
asociacion_posta = through_class
|
234
|
-
|
235
|
-
end
|
205
|
+
asociacion_posta = find_on_all_associations(through_class, campo)
|
206
|
+
|
236
207
|
raise 'no se encontró la asociacion' if asociacion_posta.nil?
|
237
208
|
|
238
209
|
asociacion_posta
|
@@ -255,18 +226,18 @@ module PgEngine
|
|
255
226
|
scope = @filtros[campo.to_sym][:scope_asociacion].call(scope)
|
256
227
|
end
|
257
228
|
|
229
|
+
# TODO: default sort
|
230
|
+
|
258
231
|
map = scope.map { |o| [o.to_s, o.id] }
|
259
232
|
|
260
233
|
content_tag :div, class: 'col-auto' do
|
261
234
|
content_tag :div, class: 'filter' do
|
262
|
-
# placeholder = ransack_placeholder(campo)
|
263
235
|
suf = extraer_sufijo(campo)
|
264
236
|
if suf.in? %w[in]
|
265
|
-
@form.select
|
266
|
-
|
237
|
+
@form.select campo, map, { multiple: true }, placeholder:, 'data-controller': 'selectize',
|
238
|
+
class: 'form-control form-control-sm pg-input-lg'
|
267
239
|
else
|
268
|
-
campo
|
269
|
-
@form.select campo, map, { include_blank: "Seleccionar #{placeholder}" }, class: 'form-select form-select-sm pg-input-lg'
|
240
|
+
@form.select campo, map, { include_blank: "Seleccionar #{placeholder.downcase}" }, class: 'form-select form-select-sm pg-input-lg'
|
270
241
|
end
|
271
242
|
end
|
272
243
|
end
|
@@ -279,36 +250,19 @@ module PgEngine
|
|
279
250
|
end
|
280
251
|
content_tag :div, class: 'col-auto' do
|
281
252
|
content_tag :div, class: 'filter' do
|
282
|
-
# placeholder = ransack_placeholder(campo)
|
283
253
|
suf = extraer_sufijo(campo)
|
284
254
|
if suf.in? %w[in]
|
285
255
|
@form.select(campo, map, { multiple: true }, placeholder:, class: 'form-control form-control-sm pg-input-lg', 'data-controller': 'selectize')
|
286
256
|
else
|
287
|
-
@form.select(campo, map, { include_blank: "Seleccionar #{placeholder}" }, placeholder:, class: 'form-select form-select-sm pg-input-lg')
|
257
|
+
@form.select(campo, map, { include_blank: "Seleccionar #{placeholder.downcase}" }, placeholder:, class: 'form-select form-select-sm pg-input-lg')
|
288
258
|
end
|
289
259
|
end
|
290
260
|
end
|
291
261
|
end
|
292
262
|
|
293
|
-
# DEPRECADO
|
294
|
-
def filtro_select_custom(campo, placeholder = '')
|
295
|
-
map = @filtros[campo.to_sym][:opciones]
|
296
|
-
unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
|
297
|
-
map.unshift ["Seleccionar #{placeholder.downcase}",
|
298
|
-
nil]
|
299
|
-
end
|
300
|
-
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
301
|
-
content_tag :div, class: 'col-auto' do
|
302
|
-
content_tag :div, class: 'filter' do
|
303
|
-
select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
|
304
|
-
end
|
305
|
-
end
|
306
|
-
end
|
307
|
-
|
308
263
|
def filtro_texto(campo, placeholder = '')
|
309
264
|
content_tag :div, class: 'col-auto' do
|
310
265
|
content_tag :div, class: 'filter' do
|
311
|
-
# placeholder = ransack_placeholder(campo)
|
312
266
|
@form.search_field(
|
313
267
|
campo, class: 'form-control form-control-sm allow-enter-submit', placeholder:, autocomplete: 'off'
|
314
268
|
)
|
@@ -317,15 +271,13 @@ module PgEngine
|
|
317
271
|
end
|
318
272
|
|
319
273
|
def filtro_boolean(campo, placeholder = '')
|
320
|
-
map = [%w[
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
end
|
325
|
-
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
274
|
+
map = [%w[Sí true], %w[No false]]
|
275
|
+
|
276
|
+
include_blank = "¿#{placeholder.titleize}?"
|
277
|
+
|
326
278
|
content_tag :div, class: 'col-auto' do
|
327
279
|
content_tag :div, class: 'filter' do
|
328
|
-
|
280
|
+
@form.select campo.to_sym, map, { include_blank: }, class: 'form-select form-select-sm pg-input-lg'
|
329
281
|
end
|
330
282
|
end
|
331
283
|
end
|
@@ -333,7 +285,6 @@ module PgEngine
|
|
333
285
|
def filtro_fecha(campo, placeholder = '')
|
334
286
|
content_tag :div, class: 'col-auto' do
|
335
287
|
content_tag :div, class: 'filter' do
|
336
|
-
# placeholder = ransack_placeholder(campo)
|
337
288
|
label_tag(nil, placeholder, class: 'text-body-secondary') +
|
338
289
|
@form.date_field(
|
339
290
|
campo, class: 'form-control form-control-sm d-inline-block w-auto ms-1', placeholder:, autocomplete: 'off'
|
@@ -342,10 +293,6 @@ module PgEngine
|
|
342
293
|
end
|
343
294
|
end
|
344
295
|
|
345
|
-
def ransack_placeholder(campo)
|
346
|
-
@form.object.translate(campo, include_associations: false)
|
347
|
-
end
|
348
|
-
|
349
296
|
def parametros_controller
|
350
297
|
params
|
351
298
|
end
|
@@ -2,12 +2,12 @@
|
|
2
2
|
|
3
3
|
wb = xlsx_package.workbook
|
4
4
|
wb.add_worksheet(name: @clase_modelo.nombre_plural) do |sheet|
|
5
|
-
headers = atributos_para_listar.map { |a| @clase_modelo.human_attribute_name(a) }
|
5
|
+
headers = atributos_para_listar.map { |a, _sort_by| @clase_modelo.human_attribute_name(a) }
|
6
6
|
headers.prepend 'ID interno'
|
7
7
|
sheet.add_row(headers)
|
8
8
|
|
9
9
|
@collection.decorate.each do |object|
|
10
|
-
array = atributos_para_listar.map do |att|
|
10
|
+
array = atributos_para_listar.map do |att, _sort_by|
|
11
11
|
object.send(att)
|
12
12
|
end
|
13
13
|
array.prepend object.to_key
|
@@ -16,7 +16,7 @@
|
|
16
16
|
|
17
17
|
- if @filtros.present? && show_filters?
|
18
18
|
.border-bottom#filtros
|
19
|
-
.d-flex.align-items-center.
|
19
|
+
.d-flex.align-items-center.px-3.py-2
|
20
20
|
.px-2.d-none.d-sm-inline-block
|
21
21
|
span.bi.bi-funnel-fill
|
22
22
|
= search_form_for @q, url: namespaced_path(@clase_modelo) do |f|
|
@@ -49,7 +49,7 @@ div
|
|
49
49
|
- @collection.each do |object|
|
50
50
|
- object = object.decorate
|
51
51
|
tr id="#{dom_id(object)}"
|
52
|
-
- atributos_para_listar.each do |att|
|
52
|
+
- atributos_para_listar.each do |att, _sort_field|
|
53
53
|
td.text-nowrap = object.send(att)
|
54
54
|
td.text-nowrap.text-end.ps-5
|
55
55
|
.actions-wrapper
|
@@ -25,6 +25,14 @@ module Arel
|
|
25
25
|
end
|
26
26
|
|
27
27
|
Ransack.configure do |config|
|
28
|
+
config.postgres_fields_sort_option = :nulls_always_last
|
29
|
+
|
30
|
+
config.custom_arrows = {
|
31
|
+
up_arrow: '<i class="bi bi-sort-up" />',
|
32
|
+
down_arrow: '<i class="bi bi-sort-down-alt" />',
|
33
|
+
default_arrow: ''
|
34
|
+
}
|
35
|
+
|
28
36
|
# Piso predicados cont y not_cont para que usen unaccent
|
29
37
|
config.add_predicate 'cont',
|
30
38
|
arel_predicate: 'matches_unaccent',
|
@@ -47,65 +47,4 @@ describe PgEngine::Resource do
|
|
47
47
|
expect(subject).to eq categoria_de_cosa
|
48
48
|
end
|
49
49
|
end
|
50
|
-
|
51
|
-
describe '#do_sort' do
|
52
|
-
subject do
|
53
|
-
instancia.send(:do_sort, scope, param, direction)
|
54
|
-
end
|
55
|
-
|
56
|
-
let!(:cosa_ult) { create :cosa, nombre: 'Z' }
|
57
|
-
let!(:cosa_pri) { create :cosa, nombre: 'a' }
|
58
|
-
let(:scope) { Cosa.all }
|
59
|
-
let(:param) { :nombre }
|
60
|
-
let(:direction) { :desc }
|
61
|
-
|
62
|
-
context 'asc' do
|
63
|
-
let(:direction) { :asc }
|
64
|
-
|
65
|
-
it do
|
66
|
-
expect(subject.to_a).to eq [cosa_pri, cosa_ult]
|
67
|
-
end
|
68
|
-
end
|
69
|
-
|
70
|
-
context 'desc' do
|
71
|
-
let(:direction) { :desc }
|
72
|
-
|
73
|
-
it do
|
74
|
-
expect(subject.to_a).to eq [cosa_ult, cosa_pri]
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
context 'cuando no existe el param' do
|
79
|
-
let(:param) { :inexistente }
|
80
|
-
|
81
|
-
it do
|
82
|
-
expect(subject.to_a).to eq [cosa_ult, cosa_pri]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
|
86
|
-
context 'cuando ordeno por categoria' do
|
87
|
-
let(:param) { :categoria_de_cosa }
|
88
|
-
|
89
|
-
before do
|
90
|
-
cosa_pri.categoria_de_cosa.update_column(:nombre, 'a')
|
91
|
-
cosa_ult.categoria_de_cosa.update_column(:nombre, 'z')
|
92
|
-
end
|
93
|
-
|
94
|
-
context 'si es asc' do
|
95
|
-
let(:direction) { :asc }
|
96
|
-
|
97
|
-
it do
|
98
|
-
expect(subject.to_a).to eq [cosa_pri, cosa_ult]
|
99
|
-
end
|
100
|
-
end
|
101
|
-
|
102
|
-
context 'si es desc' do
|
103
|
-
let(:direction) { :desc }
|
104
|
-
|
105
|
-
it do
|
106
|
-
expect(subject.to_a).to eq [cosa_ult, cosa_pri]
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
50
|
end
|
@@ -43,6 +43,20 @@ FactoryBot.define do
|
|
43
43
|
password { "password#{rand(99_999)}" }
|
44
44
|
confirmed_at { Faker::Date.backward }
|
45
45
|
|
46
|
+
transient do
|
47
|
+
account { nil }
|
48
|
+
end
|
49
|
+
|
50
|
+
after(:create) do |model, context|
|
51
|
+
if context.account
|
52
|
+
model.user_accounts.create!(account: context.account)
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
trait :orphan do
|
57
|
+
orphan { true }
|
58
|
+
end
|
59
|
+
|
46
60
|
trait :admin do
|
47
61
|
developer { true }
|
48
62
|
end
|
data/pg_rails/lib/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pg_rails
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 7.1.
|
4
|
+
version: 7.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martín Rosso
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2024-
|
11
|
+
date: 2024-08-01 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -866,6 +866,7 @@ files:
|
|
866
866
|
- pg_rails/lib/pg_rails/dotenv_support.rb
|
867
867
|
- pg_rails/lib/pg_rails/redis_support.rb
|
868
868
|
- pg_rails/lib/pg_rails/rspec_logger_matchers.rb
|
869
|
+
- pg_rails/lib/pg_rails/tom_select_helpers.rb
|
869
870
|
- pg_rails/lib/pg_rails/vcr_support.rb
|
870
871
|
- pg_rails/lib/version.rb
|
871
872
|
- pg_rails/scss/bootstrap_overrides.scss
|