base_editing_bootstrap 1.12.0 → 1.13.0

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: 220d6cba364a9462e61d4db63e648b902899d92330afe32fa7f9844f898e5793
4
- data.tar.gz: d74f68c4b7d6682b85dcde6089c41ec23a00596e848c6d7c98bcac89e14c5f67
3
+ metadata.gz: 03c295a72d7902af261c7c01405cc45a7b81d243c846f60c1974f4e07e5e648e
4
+ data.tar.gz: 5281b24d0df35c81db386217c763e266bf29affa07ca33c34632527981f5be5b
5
5
  SHA512:
6
- metadata.gz: 3b64e2d71bbed18776836d07c93dc771e33bf43d3cc465cd3b88839936ea6694f8763f928178764e5b30625416a2f83cabba59a40e879249299d52ba397f862f
7
- data.tar.gz: cc362577fa363200349af2ee2b2cb076573047d865f5b9866434c213518e1a3471b0b6dcae851d59650f5b9bb973a0bab7093dce729e45d4783147bbc68305fc
6
+ metadata.gz: cdd4c188cef1aba14fadc79888e24fbdf3dafdbcc204ec933a1558ef5fbbed0255f36924c4e327c244e8176e777452077404a3c0c23b3ebeb1c869af62bf9ae3
7
+ data.tar.gz: 74c856a196196dd319d42446c474d5ba5449cefb2d01a7333d3e20bc2b4bcbb1273777b01363381e52a0fc8abbdd9bc9249a8cd5da4cd8dc60d2e470408994f3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
  All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
3
3
 
4
4
  - - -
5
+ ## 1.13.0 - 2026-02-03
6
+ #### Features
7
+ - Form submit button inheritance value - (00b04b1) - Marino Bonetti
8
+ - Add customizability on model for form partial (#21) - (b7cead4) - Marino Bonetti
9
+ - Add BaseEditingBootstrap::Logging for form selection - (ecded89) - Marino Bonetti
10
+ #### Bug Fixes
11
+ - Warning escape - (1512271) - Marino Bonetti
12
+ - Correct submit text in case of not ActiveRecord - (6b658d4) - Marino Bonetti
13
+ #### Refactoring
14
+ - Replace `config_accessor` with `mattr_accessor` in BaseEditingBootstrap - (a4c3fb0) - Marino Bonetti
15
+ - BsLogging default tagging - (fbd4f2f) - Marino Bonetti
16
+ #### Miscellaneous Chores
17
+ - Add Ruby 4.0 as a valid version in matrix - (f32795e) - Marino Bonetti
18
+
19
+ - - -
20
+
5
21
  ## 1.12.0 - 2025-12-05
6
22
  #### Features
7
23
  - Add Capacity of custom disable action column - (4910fc3) - Marino Bonetti
data/README.md CHANGED
@@ -197,6 +197,19 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
197
197
  - default => base.html.erb
198
198
 
199
199
  **Form Field**
200
+ - CUSTOM => Nel modello, richiamare il metodo di classe per impostare il partial per lo specifico campo,
201
+ dal punto di vista del helper per ricercare il partial corretto avverrà poi il normale iter di ricerca
202
+ fra namespace di classe e namespace di controller per trovare il corretto partial:
203
+ ```ruby
204
+ class MyCustomModel < ApplicationRecord
205
+ include BaseEditingBootstrap::BaseModel
206
+ set_field_to_form_partial :title, :textarea
207
+ end
208
+ ```
209
+ E' anche disponibile un helper per testare la corretta configurazione:
210
+ ```ruby
211
+ it_behaves_like "a model with custom field_to_form_partial", :importo, :currency
212
+ ```
200
213
  - Integer => _integer.html.erb
201
214
  - Float => _decimal.html.erb
202
215
  - Decimal => _decimal.html.erb
@@ -230,8 +243,8 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
230
243
  nested attraverso quanto elencato nella policy dell'oggetto padre.
231
244
  - Default/String => _base.html.erb
232
245
 
233
- In futuro si prevede di aggiungere automatismi per renderizzare senza
234
- l'intervento dell'utente dei campi.
246
+ In futuro si prevede di aggiungere automatismi per renderizzare senza
247
+ l'intervento dell'utente dei campi.
235
248
  - [OPTIONAL] Search Form:
236
249
  Per poter aggiungere una form di ricerca basta aggiungere alla policy
237
250
  del modello in questione i campi di ricerca che verranno poi utilizzati da ransack
@@ -263,10 +276,22 @@ Fai riferimento all'implementazione di esempio del dummy `Company->addresses`
263
276
 
264
277
  ### Translations
265
278
 
266
- Traduzioni disponibili:
279
+ #### Index buttons:
267
280
  Per i bottoni della index, è possibile eseguire l'override del testo presente nel bottone.
268
281
  Leggere la documentazione nel file `app/helpers/base_editing_helper.rb#translate_with_controller_scoped`
269
282
 
283
+ #### Per i bottoni delle form(Submit):
284
+ E' possibile tradurre il contenuto del bottone andando ad impostare la traduzione direttamente in yml.
285
+ ES:
286
+ Con la class inheritance così composta: Remote < Base < ApplicationRecord < ActiveRecord::Base
287
+ per il bottone dell'oggetto Remote avremo questa ricerca:
288
+ 1. en.helpers.submit.remote.create
289
+ 2. en.helpers.submit.base.create
290
+ 3. en.helpers.submit.create
291
+
292
+ In caso di oggetto persistente verrà ricercata la chiave finale `update`
293
+
294
+
270
295
  ## Testing helpers
271
296
 
272
297
  ### Requirements(installed with generators)
@@ -4,6 +4,7 @@ module Utilities
4
4
  include EnumHelper
5
5
  include IconHelper
6
6
  include Pundit::Authorization
7
+ include BaseEditingBootstrap::Logging
7
8
  ##
8
9
  # Metodo su cui eseguire override per i campi specifici rispetto all'oggetto gestito dal controller
9
10
  # @deprecated Utilizza form_print_field(form, field) senza sovrascriverlo
@@ -20,7 +21,9 @@ module Utilities
20
21
  # @param [Symbol] field
21
22
  def form_print_field(form, field)
22
23
  locals = {form:, field:}
23
- if form.object.class.respond_to?(:defined_enums) && form.object.class.defined_enums.key?(field.to_s)
24
+ if form.object.class.respond_to?(:field_to_form_partial) and (generic_field = form.object.class.field_to_form_partial(field))
25
+ type= :custom
26
+ elsif form.object.class.respond_to?(:defined_enums) && form.object.class.defined_enums.key?(field.to_s)
24
27
  type = :enum
25
28
  generic_field = "enum"
26
29
  elsif form.object.class.respond_to?(:reflect_on_association) &&
@@ -88,13 +91,12 @@ module Utilities
88
91
  "form_field",
89
92
  generic_field
90
93
  )
91
- Rails.logger.debug do
94
+ bs_logger.debug do
92
95
  <<~TEXT
93
- [BASE EDITING BOOTSTRAP]
94
- TYPE: #{type}
95
- GENERIC_FIELD: #{generic_field}
96
- TEMPLATE: #{template.short_identifier}
97
- LOCALS:#{locals}
96
+ TYPE: #{type}
97
+ GENERIC_FIELD: #{generic_field}
98
+ TEMPLATE: #{template.short_identifier}
99
+ LOCALS:#{locals}
98
100
  TEXT
99
101
  end
100
102
  template.render(self, locals)
@@ -1,7 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Utilities::TemplateHelper
4
-
4
+ include BaseEditingBootstrap::Logging
5
5
  ##
6
6
  # Ricerca template con fallbacks.
7
7
  # In ordine, cerca di trovare il partial per l'oggetto(tramite il metodo to_partial_path) e il campo specifico.
@@ -30,21 +30,23 @@ module Utilities::TemplateHelper
30
30
  start_class = start_class.superclass
31
31
  end
32
32
 
33
- [
34
- # Precedenza modello e campo specifico
35
- ["Campo SPECIFICO + inheritance tra modelli", field, obj_base_paths],
36
- # cerco tramite nome modello semplice, con namespace della risorsa (cell_field,header_field,form_field) e nome del campo specifico
37
- ["Campo specifico con nome modello + inheritance controllers", "#{obj.model_name.element}/#{base_path}/#{field}", lookup_context.prefixes],
38
- # cerco struttura senza il livello del nome del modello
39
- ["Campo specifico senza nome modello + inheritance controllers", "#{base_path}/#{field}", lookup_context.prefixes],
40
- # Ricerca tramite campo generico e prefissi di contesto che contiene anche controller e namespace di controller
41
- ["Campo GENERICO + inheritance controllers", "#{base_path}/#{generic_field}", lookup_context.prefixes],
42
- ["Campo GENERICO + inheritance tra modelli", generic_field, obj_base_paths],
43
- ["Default BaseEditingController", "base_editing/#{base_path}/#{generic_field}", []],
44
- ].each do |desc,partial, prefixes|
45
- Rails.logger.debug { "[BASE EDITING BOOTSTRAP] #{desc} - partial:`#{partial}` in #{prefixes.inspect}" }
46
- if lookup_context.exists?(partial, prefixes, true)
47
- return lookup_context.find(partial, prefixes, true)
33
+ bs_logger.tagged(field) do
34
+ [
35
+ # Precedenza modello e campo specifico
36
+ ["Campo SPECIFICO + inheritance tra modelli", field, obj_base_paths],
37
+ # cerco tramite nome modello semplice, con namespace della risorsa (cell_field,header_field,form_field) e nome del campo specifico
38
+ ["Campo specifico con nome modello + inheritance controllers", "#{obj.model_name.element}/#{base_path}/#{field}", lookup_context.prefixes],
39
+ # cerco struttura senza il livello del nome del modello
40
+ ["Campo specifico senza nome modello + inheritance controllers", "#{base_path}/#{field}", lookup_context.prefixes],
41
+ # Ricerca tramite campo generico e prefissi di contesto che contiene anche controller e namespace di controller
42
+ ["Campo GENERICO + inheritance controllers", "#{base_path}/#{generic_field}", lookup_context.prefixes],
43
+ ["Campo GENERICO + inheritance tra modelli", generic_field, obj_base_paths],
44
+ ["Default BaseEditingController", "base_editing/#{base_path}/#{generic_field}", []],
45
+ ].each do |desc, partial, prefixes|
46
+ bs_logger.debug { "#{desc} - partial:`#{partial}` in #{prefixes.inspect}" }
47
+ if lookup_context.exists?(partial, prefixes, true)
48
+ return lookup_context.find(partial, prefixes, true)
49
+ end
48
50
  end
49
51
  end
50
52
  # fallback finale
@@ -1 +1 @@
1
- 1.12.0
1
+ 1.13.0
@@ -11,6 +11,7 @@ module BaseEditingBootstrap
11
11
  :ransackable_associations,
12
12
  :ransackable_scopes, to: :@class
13
13
 
14
+ class_attribute :_field_to_form_partial
14
15
 
15
16
  ##
16
17
  # Label da utilizzare nelle option per quando si genera le select dei belongs to
@@ -44,6 +45,25 @@ module BaseEditingBootstrap
44
45
  Pundit.policy(BaseEditingBootstrap.authentication_model.new, self.new).permitted_scopes_for_ransack.map(&:to_s)
45
46
  end
46
47
  end
48
+
49
+ ##
50
+ # Questo metodo registra sulla classe la tuppla campo e partial per impostare il
51
+ # partial da utilizzare nel rendering
52
+ #
53
+ # E' presente anche un helper per i test:
54
+ #
55
+ # it_behaves_like "a model with custom field_to_form_partial", :importo, :currency
56
+ #
57
+ def set_field_to_form_partial(field, partial)
58
+ self._field_to_form_partial ||= {}
59
+ self._field_to_form_partial = self._field_to_form_partial.merge(field => partial)
60
+ end
61
+
62
+ def field_to_form_partial(field)
63
+ return nil unless self._field_to_form_partial
64
+ self._field_to_form_partial.fetch(field, nil)
65
+ end
66
+
47
67
  end
48
68
  end
49
69
  end
@@ -106,6 +106,22 @@ module BaseEditingBootstrap::Forms
106
106
  # di seguire realmente il link con il browser.
107
107
  def submit(value = nil, options = {})
108
108
  @template.content_tag(:div, class: "btn-group mr-1") do
109
+
110
+ if value.nil? && object.respond_to?(:model_name)
111
+ key = object.respond_to?(:persisted?) ? (object.persisted? ? :update : :create) : :submit
112
+ defaults = []
113
+ tmp = object.class
114
+ while tmp != ::ActiveRecord::Base && tmp.respond_to?(:model_name)
115
+ defaults << :"helpers.submit.#{tmp.model_name.i18n_key}.#{key}"
116
+ tmp = tmp.superclass
117
+ end
118
+ defaults << :"helpers.submit.#{key}"
119
+ defaults << "_NOT_FOUND_TRANSLATION_"
120
+
121
+ value = I18n.translate(defaults.shift, model: object.model_name.human, default: defaults)
122
+ value = nil if value == "_NOT_FOUND_TRANSLATION_"
123
+ end
124
+
109
125
  super(value, options.reverse_merge(class: "btn btn-primary")) +
110
126
  @template.link_to(object.class.human_attribute_name(:_submit_undo, default: :undo),
111
127
  @template.index_custom_polymorphic_path(object.class),
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ module BaseEditingBootstrap
4
+ module Logging
5
+ def bs_logger
6
+ @logger ||= begin
7
+ config_logger = BaseEditingBootstrap.logger
8
+ config_logger = config_logger || (defined?(Rails) ? Rails.logger : Logger.new($stdout))
9
+ ActiveSupport::TaggedLogging.new(config_logger).tagged("BASE EDITING BOOTSTRAP")
10
+ end
11
+ end
12
+
13
+ end
14
+ end
@@ -16,29 +16,31 @@ loader.ignore("#{__dir__}/generators")
16
16
  loader.setup
17
17
 
18
18
  module BaseEditingBootstrap
19
- include ActiveSupport::Configurable
19
+ def self.configure
20
+ yield self
21
+ end
20
22
 
21
23
  ##
22
24
  # Controller da cui derivare poi il BaseEditingController da cui derivano
23
25
  # tutti i controller sottostanti
24
26
  # @default "ApplicationController"
25
- config_accessor :inherited_controller, default: "ApplicationController"
27
+ mattr_accessor :inherited_controller, default: "ApplicationController"
26
28
 
27
29
  ##
28
30
  # Configurazione per alterare lo standard di azione post aggiornamento record
29
31
  # il default è andare nella pagina di editing del record
30
32
  # possibili valori :edit , :index
31
- config_accessor :after_success_update_redirect, default: :edit
33
+ mattr_accessor :after_success_update_redirect, default: :edit
32
34
 
33
35
  ##
34
36
  # Configurazione per alterare lo standard di azione post creazione record
35
37
  # il default è andare nella pagina di editing del record
36
38
  # possibili valori :edit , :index
37
- config_accessor :after_success_create_redirect, default: :edit
39
+ mattr_accessor :after_success_create_redirect, default: :edit
38
40
 
39
41
  ##
40
42
  # Classe che rappresenta l'utente, solitamente User
41
- config_accessor :authentication_model_class, default: "User"
43
+ mattr_accessor :authentication_model_class, default: "User"
42
44
 
43
45
  def self.authentication_model
44
46
  self.authentication_model_class.constantize
@@ -46,12 +48,16 @@ module BaseEditingBootstrap
46
48
 
47
49
  ##
48
50
  # Factory per la creazione del modello che rappresenta l'auteticazione
49
- config_accessor :authentication_model_factory, default: :user
51
+ mattr_accessor :authentication_model_factory, default: :user
50
52
 
51
53
  def self.deprecator
52
54
  @deprecator ||= ActiveSupport::Deprecation.new("2.0", "BaseEditingBootstrap")
53
55
  end
54
56
 
57
+ ##
58
+ # Logger, default to Rails.logger
59
+ mattr_accessor :logger, default: nil
60
+
55
61
  end
56
62
 
57
63
  loader.eager_load
@@ -27,4 +27,10 @@ BaseEditingBootstrap.configure do |config|
27
27
  # Factory per la creazione del modello che rappresenta l'auteticazione
28
28
  # config.authentication_model_factory= :user
29
29
 
30
+ ##
31
+ # Logger, default to Rails.logger
32
+ # @default to Rails.logger or STDOUT if no Rails.logger
33
+ # config.logger = ActiveSupport::TaggedLogging.logger($stdout)
34
+ # config.logger = Rails.logger
35
+
30
36
  end
@@ -84,3 +84,15 @@ RSpec.shared_examples "a validated? object" do
84
84
  it { is_expected.to be_validated }
85
85
  end
86
86
  end
87
+
88
+ RSpec.shared_examples "a model with custom field_to_form_partial" do |field, partial|
89
+
90
+ it "when #{field}" do
91
+ expect(described_class.field_to_form_partial(field)).to eq partial
92
+ end
93
+
94
+ it "anything else" do
95
+ expect(described_class.field_to_form_partial(anything)).to be_nil
96
+ end
97
+
98
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: base_editing_bootstrap
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.12.0
4
+ version: 1.13.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Marino Bonetti
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-12-05 00:00:00.000000000 Z
11
+ date: 2026-02-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -400,6 +400,7 @@ files:
400
400
  - lib/base_editing_bootstrap/forms/base.rb
401
401
  - lib/base_editing_bootstrap/generators_helpers.rb
402
402
  - lib/base_editing_bootstrap/is_validated.rb
403
+ - lib/base_editing_bootstrap/logging.rb
403
404
  - lib/base_editing_bootstrap/resource_finder.rb
404
405
  - lib/base_editing_bootstrap/searches/base.rb
405
406
  - lib/base_editing_bootstrap/searches/field.rb