pg_rails 7.1.4 → 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/assets/stylesheets/pg_rails_b5.scss +13 -0
- 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/controllers/pg_engine/base_controller.rb +1 -1
- data/pg_engine/app/helpers/pg_engine/index_helper.rb +29 -30
- data/pg_engine/app/lib/pg_engine/filtros_builder.rb +81 -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
|
@@ -80,6 +80,19 @@ input[type=datetime-local], input[type=datetime] {
|
|
80
80
|
// max-width: 17em;
|
81
81
|
}
|
82
82
|
|
83
|
+
.filter label {
|
84
|
+
font-size: 0.8em;
|
85
|
+
font-weight: bold;
|
86
|
+
max-width: 5em;
|
87
|
+
text-align: right;
|
88
|
+
line-height: 1.2em;
|
89
|
+
vertical-align: middle;
|
90
|
+
opacity: 0.5;
|
91
|
+
min-width: 1em!important;
|
92
|
+
padding-left: 0.5em;
|
93
|
+
width: min-content;
|
94
|
+
}
|
95
|
+
|
83
96
|
// Modal
|
84
97
|
.modal-content {
|
85
98
|
box-shadow: 15px 15px 9px 0px rgba(0, 0, 0, 0.6);
|
@@ -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
|
@@ -91,7 +91,7 @@ module PgEngine
|
|
91
91
|
end
|
92
92
|
|
93
93
|
if Current.user.present?
|
94
|
-
@notifications = Current.user.notifications.order(id: :desc)
|
94
|
+
@notifications = Current.user.notifications.order(id: :desc).includes(:event)
|
95
95
|
.where(type: 'SimpleUserNotifier::Notification')
|
96
96
|
unseen = @notifications.unseen.any?
|
97
97
|
# FIXME: testear y fixear, buscar el primero que esté present
|
@@ -2,43 +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/, '')
|
8
|
-
|
9
|
-
|
10
|
-
field = controller.instance_variable_get(:@field)
|
11
|
-
direction = controller.instance_variable_get(:@direction)
|
12
|
-
uri = URI.parse(request.url)
|
13
|
-
cgi = if uri.query.present?
|
14
|
-
CGI.parse(uri.query)
|
15
|
-
else
|
16
|
-
{}
|
17
|
-
end
|
18
|
-
cgi['order_by'] = campo
|
19
|
-
cgi['order_direction'] =
|
20
|
-
if field.to_s == campo.to_s && direction.to_s == 'desc'
|
21
|
-
'asc'
|
22
|
-
else
|
23
|
-
'desc'
|
24
|
-
end
|
15
|
+
sort_field = sort_field.to_s.sub(/_f\z/, '')
|
16
|
+
sort_field = sort_field.to_s.sub(/_text\z/, '')
|
25
17
|
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
'<i class="bi bi-sort-up" />'
|
31
|
-
end
|
32
|
-
else
|
33
|
-
''
|
34
|
-
end
|
18
|
+
clase = options[:clase] || @clase_modelo
|
19
|
+
key = [controller_name, action_name, 'listado_header', campo].join('.')
|
20
|
+
dflt = :"activerecord.attributes.#{clase.model_name.i18n_key}.#{campo}"
|
21
|
+
human_name = clase.human_attribute_name(key, default: dflt)
|
35
22
|
|
36
|
-
|
23
|
+
if options[:ordenable]
|
24
|
+
sort_link(@q, sort_field, human_name, default_order: default_order(campo))
|
25
|
+
else
|
26
|
+
human_name
|
27
|
+
end
|
28
|
+
end
|
37
29
|
|
38
|
-
|
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
|
39
34
|
else
|
40
|
-
|
35
|
+
:asc
|
41
36
|
end
|
37
|
+
rescue StandardError => e
|
38
|
+
pg_err e
|
39
|
+
|
40
|
+
:asc
|
42
41
|
end
|
43
42
|
end
|
44
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,28 +124,39 @@ 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
|
|
179
141
|
def placeholder_campo(campo)
|
180
142
|
suf = extraer_sufijo(campo)
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
143
|
+
key = [controller_name, action_name, 'filter', sin_sufijo(campo)].join('.')
|
144
|
+
dflt = :"activerecord.attributes.#{@clase_modelo.model_name.i18n_key}.#{sin_sufijo(campo)}"
|
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 }
|
186
155
|
end
|
187
156
|
|
188
157
|
def filtros_html(options = {})
|
189
158
|
@form = options[:form]
|
159
|
+
|
190
160
|
raise PgEngine::Error, 'se debe setear el form' if @form.blank?
|
191
161
|
|
192
162
|
res = ''
|
@@ -198,8 +168,6 @@ module PgEngine
|
|
198
168
|
end
|
199
169
|
|
200
170
|
res += case tipo(campo)
|
201
|
-
when :select_custom
|
202
|
-
filtro_select_custom(campo, placeholder_campo(campo))
|
203
171
|
when :enumerized
|
204
172
|
filtro_select(campo, placeholder_campo(campo))
|
205
173
|
when :asociacion
|
@@ -212,24 +180,30 @@ module PgEngine
|
|
212
180
|
filtro_texto(campo, placeholder_campo(campo))
|
213
181
|
end
|
214
182
|
end
|
215
|
-
|
216
|
-
|
183
|
+
|
184
|
+
if params[:q] && params[:q][:s]
|
185
|
+
res += @form.hidden_field('s', value: params[:q][:s])
|
186
|
+
end
|
187
|
+
|
217
188
|
res.html_safe
|
218
189
|
end
|
219
190
|
|
220
|
-
def
|
191
|
+
def find_on_all_associations(klass, campo)
|
221
192
|
nombre_campo = sin_sufijo(campo)
|
222
|
-
|
223
|
-
|
224
|
-
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
|
225
195
|
end
|
196
|
+
end
|
197
|
+
|
198
|
+
def obtener_asociacion(campo)
|
199
|
+
asociacion = find_on_all_associations(@clase_modelo, campo)
|
200
|
+
|
226
201
|
raise 'no se encontró la asociacion' if asociacion.nil?
|
227
202
|
|
228
203
|
if asociacion.instance_of?(ActiveRecord::Reflection::ThroughReflection)
|
229
204
|
through_class = asociacion.through_reflection.class_name.constantize
|
230
|
-
asociacion_posta = through_class
|
231
|
-
|
232
|
-
end
|
205
|
+
asociacion_posta = find_on_all_associations(through_class, campo)
|
206
|
+
|
233
207
|
raise 'no se encontró la asociacion' if asociacion_posta.nil?
|
234
208
|
|
235
209
|
asociacion_posta
|
@@ -238,7 +212,7 @@ module PgEngine
|
|
238
212
|
end
|
239
213
|
end
|
240
214
|
|
241
|
-
def filtro_asociacion(campo,
|
215
|
+
def filtro_asociacion(campo, placeholder = '')
|
242
216
|
asociacion = obtener_asociacion(campo)
|
243
217
|
nombre_clase = asociacion.options[:class_name]
|
244
218
|
nombre_clase = asociacion.name.to_s.camelize if nombre_clase.nil?
|
@@ -252,18 +226,18 @@ module PgEngine
|
|
252
226
|
scope = @filtros[campo.to_sym][:scope_asociacion].call(scope)
|
253
227
|
end
|
254
228
|
|
229
|
+
# TODO: default sort
|
230
|
+
|
255
231
|
map = scope.map { |o| [o.to_s, o.id] }
|
256
232
|
|
257
233
|
content_tag :div, class: 'col-auto' do
|
258
234
|
content_tag :div, class: 'filter' do
|
259
|
-
placeholder = ransack_placeholder(campo)
|
260
235
|
suf = extraer_sufijo(campo)
|
261
236
|
if suf.in? %w[in]
|
262
|
-
@form.select
|
263
|
-
|
237
|
+
@form.select campo, map, { multiple: true }, placeholder:, 'data-controller': 'selectize',
|
238
|
+
class: 'form-control form-control-sm pg-input-lg'
|
264
239
|
else
|
265
|
-
campo
|
266
|
-
@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'
|
267
241
|
end
|
268
242
|
end
|
269
243
|
end
|
@@ -276,36 +250,19 @@ module PgEngine
|
|
276
250
|
end
|
277
251
|
content_tag :div, class: 'col-auto' do
|
278
252
|
content_tag :div, class: 'filter' do
|
279
|
-
placeholder = ransack_placeholder(campo)
|
280
253
|
suf = extraer_sufijo(campo)
|
281
254
|
if suf.in? %w[in]
|
282
255
|
@form.select(campo, map, { multiple: true }, placeholder:, class: 'form-control form-control-sm pg-input-lg', 'data-controller': 'selectize')
|
283
256
|
else
|
284
|
-
@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')
|
285
258
|
end
|
286
259
|
end
|
287
260
|
end
|
288
261
|
end
|
289
262
|
|
290
|
-
# DEPRECADO
|
291
|
-
def filtro_select_custom(campo, placeholder = '')
|
292
|
-
map = @filtros[campo.to_sym][:opciones]
|
293
|
-
unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
|
294
|
-
map.unshift ["Seleccionar #{placeholder.downcase}",
|
295
|
-
nil]
|
296
|
-
end
|
297
|
-
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
298
|
-
content_tag :div, class: 'col-auto' do
|
299
|
-
content_tag :div, class: 'filter' do
|
300
|
-
select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
|
301
|
-
end
|
302
|
-
end
|
303
|
-
end
|
304
|
-
|
305
263
|
def filtro_texto(campo, placeholder = '')
|
306
264
|
content_tag :div, class: 'col-auto' do
|
307
265
|
content_tag :div, class: 'filter' do
|
308
|
-
placeholder = ransack_placeholder(campo)
|
309
266
|
@form.search_field(
|
310
267
|
campo, class: 'form-control form-control-sm allow-enter-submit', placeholder:, autocomplete: 'off'
|
311
268
|
)
|
@@ -314,15 +271,13 @@ module PgEngine
|
|
314
271
|
end
|
315
272
|
|
316
273
|
def filtro_boolean(campo, placeholder = '')
|
317
|
-
map = [%w[
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
end
|
322
|
-
default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
|
274
|
+
map = [%w[Sí true], %w[No false]]
|
275
|
+
|
276
|
+
include_blank = "¿#{placeholder.titleize}?"
|
277
|
+
|
323
278
|
content_tag :div, class: 'col-auto' do
|
324
279
|
content_tag :div, class: 'filter' do
|
325
|
-
|
280
|
+
@form.select campo.to_sym, map, { include_blank: }, class: 'form-select form-select-sm pg-input-lg'
|
326
281
|
end
|
327
282
|
end
|
328
283
|
end
|
@@ -330,7 +285,6 @@ module PgEngine
|
|
330
285
|
def filtro_fecha(campo, placeholder = '')
|
331
286
|
content_tag :div, class: 'col-auto' do
|
332
287
|
content_tag :div, class: 'filter' do
|
333
|
-
placeholder = ransack_placeholder(campo)
|
334
288
|
label_tag(nil, placeholder, class: 'text-body-secondary') +
|
335
289
|
@form.date_field(
|
336
290
|
campo, class: 'form-control form-control-sm d-inline-block w-auto ms-1', placeholder:, autocomplete: 'off'
|
@@ -339,10 +293,6 @@ module PgEngine
|
|
339
293
|
end
|
340
294
|
end
|
341
295
|
|
342
|
-
def ransack_placeholder(campo)
|
343
|
-
@form.object.translate(campo, include_associations: false)
|
344
|
-
end
|
345
|
-
|
346
296
|
def parametros_controller
|
347
297
|
params
|
348
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
|