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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 97005ad0cfff2f7088c2dbfe667e1fc8339b8873c3935580d374069fdda0c463
4
- data.tar.gz: 938afdb82665e744d1c352e5879523329064bb5cadc7c9becdd88bb6aa85505e
3
+ metadata.gz: e9ea11adc017949414ed89c42127ce6867418dcd461219fb56289a2832a938a6
4
+ data.tar.gz: 30ab308185ff7e68acebf1611161f55fa5d783bc95536db27a2026091637d69a
5
5
  SHA512:
6
- metadata.gz: ce4389f063db55a1761fa50c4335a5b7c98825222b7c541accd5f3e8b4e65c13f9a7ebe3a65787b7c90219f90f11370136faf1efb98f2b2996d9047fc8707e86
7
- data.tar.gz: 6a510173f026e874693cc471f9eb251b733164f3cfc1fd72f105b9b556e7cf918962340584e1479d47d130ba723d0c5642a97f3b8097f417c84d7bf495a53c97
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);
@@ -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
@@ -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(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/, '')
8
- clase = options[:clase] || @clase_modelo
9
- if options[:ordenable]
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
- symbol = if field.to_s == campo.to_s
27
- if direction.to_s == 'asc'
28
- '<i class="bi bi-sort-down-alt" />'
29
- elsif direction.to_s == 'desc'
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
- uri.query = cgi.transform_values { |b| (b.length == 1 ? b.first : b) }.to_query
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
- link_to(clase.human_attribute_name(campo), uri.to_s) + " #{symbol}".html_safe
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
- clase.human_attribute_name(campo)
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
- SUFIJOS = %w[desde hasta incluye es_igual_a in cont 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,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
- if suf.present?
182
- "#{@clase_modelo.human_attribute_name(sin_sufijo(campo))} #{suf}"
183
- else
184
- @clase_modelo.human_attribute_name(campo)
185
- end
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
- res += hidden_field_tag('order_by', parametros_controller['order_by'])
216
- 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
+
217
188
  res.html_safe
218
189
  end
219
190
 
220
- def obtener_asociacion(campo)
191
+ def find_on_all_associations(klass, campo)
221
192
  nombre_campo = sin_sufijo(campo)
222
- extraer_sufijo(campo)
223
- asociacion = @clase_modelo.reflect_on_all_associations.find do |a|
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.reflect_on_all_associations.find do |a|
231
- a.name == nombre_campo.to_sym
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, _placeholder = '')
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 sin_sufijo(campo) + '_id_in', map, { multiple: true }, placeholder:, 'data-controller': 'selectize',
263
- 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'
264
239
  else
265
- campo = campo.to_s + '_id_eq'
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[Si si], %w[No no]]
318
- unless @filtros[campo.to_sym].present? && @filtros[campo.to_sym][:include_blank] == false
319
- map.unshift ["¿#{placeholder.titleize}?",
320
- nil]
321
- end
322
- default = parametros_controller[campo].nil? ? nil : parametros_controller[campo]
274
+ map = [%w[ 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
- 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'
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
@@ -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.4'
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.4
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