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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0aaf9f6d48a4411856efca24dfbe0e1f27fe03202c2f5fc5f5c45b628f5142e9
4
- data.tar.gz: a342d47cac9298e1a29ffab6222f7c66cf36aa48c15119330eed2efb258c369d
3
+ metadata.gz: e9ea11adc017949414ed89c42127ce6867418dcd461219fb56289a2832a938a6
4
+ data.tar.gz: 30ab308185ff7e68acebf1611161f55fa5d783bc95536db27a2026091637d69a
5
5
  SHA512:
6
- metadata.gz: 4de79ebcc76b2d4d04b0709d18f0ae5106019a16eec4cee8272708b33aba4476980d0563f7c0569bde685638614b91a5ee5197fb750f21bbd10862176ea429e8
7
- data.tar.gz: 2f3b8bd20aee78bd24133777fd6660a919cfa10b66d581ff13b0a0ce60adae8061401e08966c994aed86bedaa08d5cfbc4bcb90c4d07217c39f3a3654e7d58ba
6
+ metadata.gz: 61685a1f498123e153ae0a635805566b69dbf177ad079da95e53221b81c05af957cdc9d8d0de63004d48d74801cf493a7062f303c227f9cdffa08a5834442941
7
+ data.tar.gz: 6c80c211396d351891a1c4071672bae515a629d933a128cd3e9f3b5fae4d948e624b9577645cee199bd10e4d6aa55b1aafa1278e4011dc7d1e7a87a60efede3e
@@ -53,7 +53,7 @@ module Admin
53
53
  end
54
54
 
55
55
  def atributos_para_buscar
56
- %i[email_cont nombre_cont apellido_cont developer]
56
+ %i[email nombre apellido developer]
57
57
  end
58
58
 
59
59
  def atributos_para_listar
@@ -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.for(clase_modelo)
24
-
23
+ shared_context = Ransack::Adapters::ActiveRecord::Context.new(@collection)
25
24
  @q = @clase_modelo.ransack(params[:q], context: shared_context)
26
- # @collection = @q.result(distinct: true)
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('body', partial: 'pg_layout/modal_show', locals: { object: })
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(campo, options = {})
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
- link_to(human_name, uri.to_s) + " #{symbol}".html_safe
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
- SUFIJOS = %w[desde hasta gt gte lt lte incluye es_igual_a in cont cont_all eq].freeze
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.reflect_on_all_associations.find do |a|
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
- Rails.logger.warn("no existe el campo: #{nombre_campo}")
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
- humann = @clase_modelo.human_attribute_name(key, default: dflt)
184
- if suf.present?
185
- "#{humann} #{I18n.t(suf, scope: 'ransack.predicates')}".strip.tap { _1[0] = _1[0].capitalize }
186
- else
187
- humann
188
- end
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
- res += hidden_field_tag('order_by', parametros_controller['order_by'])
219
- res += hidden_field_tag('order_direction', parametros_controller['order_direction'])
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 obtener_asociacion(campo)
191
+ def find_on_all_associations(klass, campo)
224
192
  nombre_campo = sin_sufijo(campo)
225
- extraer_sufijo(campo)
226
- asociacion = @clase_modelo.reflect_on_all_associations.find do |a|
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.reflect_on_all_associations.find do |a|
234
- a.name == nombre_campo.to_sym
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 sin_sufijo(campo) + '_id_in', map, { multiple: true }, placeholder:, 'data-controller': 'selectize',
266
- class: 'form-control form-control-sm pg-input-lg'
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 = campo.to_s + '_id_eq'
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[Si si], %w[No no]]
321
- unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
322
- map.unshift ["¿#{placeholder.titleize}?",
323
- nil]
324
- end
325
- default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
274
+ map = [%w[ 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
- select_tag campo, options_for_select(map, default), class: 'form-select form-select-sm pg-input-lg'
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
@@ -89,8 +89,8 @@ module PgEngine
89
89
  end
90
90
 
91
91
  def objeto_borrado?
92
- if record.respond_to?(:discarded?)
93
- record.discarded?
92
+ if record.respond_to?(:kept?)
93
+ !record.kept?
94
94
  else
95
95
  false
96
96
  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.p-2
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',
@@ -3,10 +3,14 @@ es:
3
3
  predicates:
4
4
  cont: ''
5
5
  cont_all: ''
6
+ cont_any: ''
7
+ not_cont: 'no contiene'
6
8
  in: ''
7
9
  eq: ''
8
10
  lt: 'hasta'
9
11
  gt: 'desde'
12
+ lteq: 'hasta'
13
+ gteq: 'desde'
10
14
  pg_engine:
11
15
  base:
12
16
  index:
@@ -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
@@ -0,0 +1,9 @@
1
+ module PgRails
2
+ module TomSelectHelpers
3
+ def select_tom(placeholder:, text:)
4
+ find("input[placeholder=\"#{placeholder}\"]").click
5
+ find('.ts-wrapper [role="option"]', text:).click
6
+ send_keys :escape
7
+ end
8
+ end
9
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module PgRails
4
- VERSION = '7.1.5'
4
+ VERSION = '7.1.6'
5
5
  end
@@ -26,7 +26,6 @@ class <%= controller_class_name.split('::').last %>Controller < <%= parent_contr
26
26
  end
27
27
 
28
28
  def atributos_para_buscar
29
- # FIXME: append _cont
30
29
  %i[<%= atributos_a_filtrar.map(&:name).join(' ') %>]
31
30
  end
32
31
 
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.5
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-07-31 00:00:00.000000000 Z
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