pg_rails 7.1.5 → 7.1.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0aaf9f6d48a4411856efca24dfbe0e1f27fe03202c2f5fc5f5c45b628f5142e9
4
- data.tar.gz: a342d47cac9298e1a29ffab6222f7c66cf36aa48c15119330eed2efb258c369d
3
+ metadata.gz: 41573d568a1fd99ec4100b77846b882c23aadbbf732bb95ddfd066d0c486f095
4
+ data.tar.gz: dff45b87624e0913445bd7c39a4a9868e02786fb6fcddc0bc2693886aeb368dc
5
5
  SHA512:
6
- metadata.gz: 4de79ebcc76b2d4d04b0709d18f0ae5106019a16eec4cee8272708b33aba4476980d0563f7c0569bde685638614b91a5ee5197fb750f21bbd10862176ea429e8
7
- data.tar.gz: 2f3b8bd20aee78bd24133777fd6660a919cfa10b66d581ff13b0a0ce60adae8061401e08966c994aed86bedaa08d5cfbc4bcb90c4d07217c39f3a3654e7d58ba
6
+ metadata.gz: 8e94ff6ffb27953e99d8dd053acd9154cb8dec89aff6ee7bdbcfce39214faf5ce9a82d08a8ea95d7717d07ba85a536d9e6c2115431edb1e28296abbc333c4e5c
7
+ data.tar.gz: f303020f87d6eb6890c6ea13790a8c5c93a4294f44e23188560d8485e48f3999d59902c4d0b48245fbb3e41887678e817df7186c0bddeacdbbdc8bec044a7d6e
@@ -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,6 @@ 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
-
25
- @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)
30
-
31
- @collection = sort_collection(@collection)
32
23
  pg_respond_index
33
24
  end
34
25
 
@@ -159,7 +150,9 @@ module PgEngine
159
150
  def pg_respond_show(object = nil)
160
151
  object ||= instancia_modelo
161
152
  if params[:modal].present?
162
- render turbo_stream: turbo_stream.append_all('body', partial: 'pg_layout/modal_show', locals: { object: })
153
+ render turbo_stream: turbo_stream.append_all(
154
+ 'body', partial: 'pg_layout/modal_show', locals: { object: }
155
+ )
163
156
  else
164
157
  respond_to do |format|
165
158
  format.json { render json: object }
@@ -295,7 +288,11 @@ module PgEngine
295
288
  )
296
289
  scope = policy_scope(clase_modelo)
297
290
 
298
- @filtros.filtrar(scope)
291
+ scope = @filtros.filtrar(scope)
292
+
293
+ shared_context = Ransack::Adapters::ActiveRecord::Context.new(scope)
294
+ @q = @clase_modelo.ransack(params[:q], context: shared_context)
295
+ shared_context.evaluate(@q)
299
296
  end
300
297
 
301
298
  def default_scope_for_current_model
@@ -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.7'
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.7
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