base_editing_bootstrap 1.8.1 → 1.10.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 +4 -4
- data/CHANGELOG.md +25 -0
- data/README.md +105 -52
- data/app/helpers/utilities/form_helper.rb +8 -2
- data/app/helpers/utilities/page_helper.rb +11 -2
- data/app/helpers/utilities/template_helper.rb +22 -8
- data/app/views/base_editing/_nested_row_form.html.erb +16 -0
- data/app/views/base_editing/form_field/_accept_nested_field.html.erb +48 -0
- data/config/locales/it.yml +1 -5
- data/lib/base_editing_bootstrap/VERSION +1 -1
- data/lib/base_editing_bootstrap/base_model.rb +3 -3
- data/lib/base_editing_bootstrap/forms/base.rb +8 -2
- data/lib/base_editing_bootstrap/generators_helpers.rb +24 -0
- data/lib/base_editing_bootstrap.rb +13 -1
- data/lib/generators/base_editing_bootstrap/cell_override/cell_override_generator.rb +4 -3
- data/lib/generators/base_editing_bootstrap/field_override/field_override_generator.rb +5 -3
- data/lib/generators/base_editing_bootstrap/header_override/header_override_generator.rb +5 -3
- data/lib/generators/base_editing_bootstrap/install/install_generator.rb +10 -0
- data/lib/generators/base_editing_bootstrap/install/templates/initializer.rb +8 -0
- data/lib/generators/base_editing_bootstrap/scaffold/templates/policy.rb.tt +19 -3
- data/spec/support/external_shared/base_editing_controller_helpers.rb +25 -14
- data/spec/support/external_shared/base_model.rb +2 -2
- data/spec/support/external_shared/factory_bot.rb +1 -0
- data/spec/support/external_shared/pundit.rb +3 -3
- metadata +5 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 489e2ffcb61b916547f555b4b80a90e9d542c0738afb83dd104418e29865a542
|
4
|
+
data.tar.gz: 3f7cba0e07451401983eeef463ff0a18ad97f2aee1a5c16a836980d4e77e4ca3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 2e62893f671fe1ef62e0c9fe52cef3c104fdab7646bb1a03b774ae9d9c5650f288e7329b5e4c5e29fda3f935c0e3706a1af8ecb90b220a16fa1f6f5e8759e726
|
7
|
+
data.tar.gz: 52055575f2459020e2963d8af95da7c904c3301cf8c4127685a1529f062ab884d9fa77fe59b22b3ff20234e23b5ee0d5db84ae9cfc472cda58ea7748cf63ec9c
|
data/CHANGELOG.md
CHANGED
@@ -2,6 +2,31 @@
|
|
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.10.0 - 2025-09-12
|
6
|
+
#### Features
|
7
|
+
- Automatic Nested attributes - (dad38de) - Marino Bonetti
|
8
|
+
|
9
|
+
- - -
|
10
|
+
|
11
|
+
## 1.9.0 - 2025-07-30
|
12
|
+
#### Bug Fixes
|
13
|
+
- Correct add is-invalid class on relation fields - (21e4a92) - Marino Bonetti
|
14
|
+
- Correct path generator for namespaced resources - (a4f72c8) - Marino Bonetti
|
15
|
+
- Migliore formattazione generatore - (1ceda4d) - Marino Bonetti
|
16
|
+
- Creazione dei nested attributi necessari con belongs to - (564f61b) - Marino Bonetti
|
17
|
+
- Correct Shared Specs - (1994128) - Marino Bonetti
|
18
|
+
- Authentication Model configurable (#19) - (cef424f) - Marino Bonetti
|
19
|
+
- Errore Traduzione di test - (95ff702) - Marino Bonetti
|
20
|
+
#### Documentation
|
21
|
+
- Add info on test matrix - (b097a01) - Marino Bonetti
|
22
|
+
#### Features
|
23
|
+
- Configurable test controller requests - (327163e) - Marino Bonetti
|
24
|
+
- In caso di molti attributi struttura multilinea - (21dfe09) - Marino Bonetti
|
25
|
+
- Add customizable title New and Edit - (d484e23) - Marino Bonetti
|
26
|
+
- Check model inheritance for partial search (#18) - (14f081f) - Marino Bonetti
|
27
|
+
|
28
|
+
- - -
|
29
|
+
|
5
30
|
## 1.8.1 - 2025-03-24
|
6
31
|
#### Bug Fixes
|
7
32
|
- Correct generator install multiple gems - (73948f5) - Marino Bonetti
|
data/README.md
CHANGED
@@ -1,9 +1,14 @@
|
|
1
1
|
# BaseEditingBootstrap
|
2
|
+
|
2
3
|
[](https://badge.fury.io/rb/base_editing_bootstrap)
|
3
4
|
|
4
|
-
|
5
|
+
### Active tested on:
|
6
|
+
|
7
|
+
* rails: 7.x,8.x
|
8
|
+
* ruby: 3.x
|
5
9
|
|
6
10
|
## Installation
|
11
|
+
|
7
12
|
Add this line to your application's Gemfile:
|
8
13
|
|
9
14
|
```ruby
|
@@ -11,29 +16,46 @@ gem "base_editing_bootstrap"
|
|
11
16
|
```
|
12
17
|
|
13
18
|
And then execute:
|
19
|
+
|
14
20
|
```bash
|
15
21
|
$ bundle
|
16
22
|
```
|
17
23
|
|
18
24
|
Or install it yourself as:
|
25
|
+
|
19
26
|
```bash
|
20
27
|
$ gem install base_editing_bootstrap
|
21
28
|
```
|
22
29
|
|
23
30
|
Then run installer:
|
31
|
+
|
24
32
|
```bash
|
25
33
|
$ bundle exec rails g base_editing_bootstrap:install
|
26
34
|
```
|
27
35
|
|
28
36
|
**Si presume quindi che ActiveStorage sia correttamente installato, completo del javascript per il direct upload**
|
29
37
|
|
38
|
+
### Note for NestedAttributes
|
39
|
+
|
40
|
+
Seguire le istruzioni per installare anche NestedAttributeForm Controller per stimulus:
|
41
|
+
|
42
|
+
```shell
|
43
|
+
bin/importmap pin @stimulus-components/rails-nested-form
|
44
|
+
```
|
45
|
+
|
46
|
+
e seguire installazione https://www.stimulus-components.com/docs/stimulus-rails-nested-form
|
47
|
+
|
30
48
|
### Generators
|
49
|
+
|
31
50
|
Then Install dependency (if you run base_editing_bootstrap:install you are good to go):
|
51
|
+
|
32
52
|
```bash
|
33
53
|
|
34
54
|
bundle exec rails g pundit:install
|
35
55
|
```
|
36
|
-
|
56
|
+
|
57
|
+
Aggiungere ad ApplicationController
|
58
|
+
|
37
59
|
```ruby
|
38
60
|
include Pundit::Authorization
|
39
61
|
```
|
@@ -46,40 +68,43 @@ documentazione e avrete la vostra versione di boostrap installata.
|
|
46
68
|
Installare `gem "factory_bot_rails"`
|
47
69
|
|
48
70
|
### Initializers
|
71
|
+
|
49
72
|
E' possibile configurare BaseEditingBootstrap con alcune impostazioni:
|
73
|
+
|
50
74
|
```ruby
|
51
75
|
BaseEditingBootstrap.configure do |config|
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
76
|
+
##
|
77
|
+
# Controller da cui derivare poi il BaseEditingController da cui derivano
|
78
|
+
# tutti i controller sottostanti
|
79
|
+
# @default "ApplicationController"
|
80
|
+
# config.inherited_controller = 'ApplicationController'
|
81
|
+
|
82
|
+
##
|
83
|
+
# Configurazione per alterare lo standard di azione post aggiornamento record
|
84
|
+
# il default è andare nella pagina di editing del record
|
85
|
+
# possibili valori :edit , :index
|
86
|
+
# config_accessor :after_success_update_redirect, default: :edit
|
87
|
+
|
88
|
+
##
|
89
|
+
# Configurazione per alterare lo standard di azione post creazione record
|
90
|
+
# il default è andare nella pagina di editing del record
|
91
|
+
# possibili valori :edit , :index
|
92
|
+
# config_accessor :after_success_create_redirect, default: :edit
|
93
|
+
|
94
|
+
end
|
71
95
|
|
72
96
|
```
|
73
97
|
|
74
98
|
## Usage
|
99
|
+
|
75
100
|
Utilizzo per modello base, in questo esempio prendiamo come modello Post come esempio del dummy.
|
76
101
|
|
77
|
-
- Creare il Modello ed includere
|
102
|
+
- Creare il Modello ed includere
|
78
103
|
```ruby
|
79
104
|
include BaseEditingBootstrap::BaseModel
|
80
105
|
```
|
81
106
|
- La factory nelle spec deve contenere il trait `with_invalid_attributes` per definire la situazione di dati per record
|
82
|
-
non valido. ES:
|
107
|
+
non valido. ES:
|
83
108
|
```ruby
|
84
109
|
trait :with_invalid_attributes do
|
85
110
|
name {nil} # name dovrebbe essere obbligatorio nel modello
|
@@ -124,13 +149,13 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
|
|
124
149
|
```shell
|
125
150
|
rails g base_editing_bootstrap:field_override ModelName field1 field2:type
|
126
151
|
```
|
127
|
-
- è possibile customizzare
|
128
|
-
- un text help per ogni campo andando ad aggiungere nelle traduzioni la relativa
|
152
|
+
- è possibile customizzare
|
153
|
+
- un text help per ogni campo andando ad aggiungere nelle traduzioni la relativa
|
129
154
|
traduzione nella posizione: `it.activerecord.attributes.MODEL.FIELD/help_text` oppure `help_text_html` in caso di
|
130
155
|
contenuto con html
|
131
|
-
- un blocco per l'unità di misura accanto al campo aggiungendo alle traduzioni:
|
156
|
+
- un blocco per l'unità di misura accanto al campo aggiungendo alle traduzioni:
|
132
157
|
`it.activerecord.attributes.MODEL.FIELD/unit`
|
133
|
-
|
158
|
+
|
134
159
|
- [OPTIONAL] la medesima cosa è possibile fare con il rendering dei campi
|
135
160
|
delle celle della tabella
|
136
161
|
```shell
|
@@ -146,48 +171,51 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
|
|
146
171
|
**Cell Field**:
|
147
172
|
- created_at => timestamps.html.erb
|
148
173
|
- updated_at => timestamps.html.erb
|
149
|
-
- Enum
|
174
|
+
- Enum => _enum.html.erb
|
150
175
|
Per gli enum, le traduzioni dei labels di ogni valore provengono da i18n
|
151
176
|
attraverso l'helper: `Utilities::EnumHelper#enum_translation` con variant `:cell_field`
|
152
177
|
il quale sfrutta human_attribute_name del modello con 'attributo.enum_value',
|
153
178
|
quindi ad esempio per un modello `Post` con enum `categoria` e un enum `importante`, la ricerca nelle traduzioni
|
154
179
|
saranno così composte:
|
155
180
|
- it.activerecord.attributes.post/categoria.importante_cell_field
|
156
|
-
- it.activerecord.attributes.categoria.importante_cell_field
|
181
|
+
- it.activerecord.attributes.categoria.importante_cell_field
|
157
182
|
- it.attributes.importante_cell_field
|
158
183
|
- it.activerecord.attributes.post/categoria.importante
|
159
184
|
- it.activerecord.attributes.categoria.importante
|
160
185
|
- it.attributes.importante => nil
|
161
|
-
- default
|
162
|
-
|
186
|
+
- default => base.html.erb
|
187
|
+
|
163
188
|
**Form Field**
|
164
|
-
- Integer
|
165
|
-
- Float
|
166
|
-
- Decimal
|
167
|
-
- DateTime
|
168
|
-
- Date
|
169
|
-
- Boolean
|
170
|
-
- Enum
|
189
|
+
- Integer => _integer.html.erb
|
190
|
+
- Float => _decimal.html.erb
|
191
|
+
- Decimal => _decimal.html.erb
|
192
|
+
- DateTime => _datetime.html.erb
|
193
|
+
- Date => _date.html.erb
|
194
|
+
- Boolean => _boolean.html.erb
|
195
|
+
- Enum => _enum.html.erb
|
171
196
|
Per gli enum, le traduzioni dei labels di ogni valore provengono da i18n
|
172
197
|
attraverso l'helper: `Utilities::EnumHelper#enum_translation`" con variante `:form_field`
|
173
|
-
il quale sfrutta human_attribute_name del modello con 'attributo.enum_value',
|
198
|
+
il quale sfrutta human_attribute_name del modello con 'attributo.enum_value',
|
174
199
|
quindi ad esempio per un modello `Post` con enum `categoria` e un enum `importante`, la ricerca nelle traduzioni
|
175
|
-
saranno così composte:
|
200
|
+
saranno così composte:
|
176
201
|
- it.activerecord.attributes.post/categoria.importante_form_field
|
177
202
|
- it.activerecord.attributes.categoria.importante_form_field
|
178
203
|
- it.attributes.importante_form_field
|
179
204
|
- it.activerecord.attributes.post/categoria.importante
|
180
205
|
- it.activerecord.attributes.categoria.importante
|
181
206
|
- it.attributes.importante => nil
|
182
|
-
- belongs_to
|
207
|
+
- belongs_to => _belongs_to_select.html.erb
|
183
208
|
Come si può leggere dal partial, il modello che viene utilizzato come base dati per la collection deve
|
184
209
|
avere come metodo `option_label` che deve ritornare la label da utilizzare nelle options.
|
185
210
|
Di default questo metodo utilizza il semplice #to_s
|
186
211
|
Ha anche un metodo per il valore da utilizzare come chiave, di default viene dedotto dalla reflection
|
187
212
|
come anche il nome della classe da utilizzare come sorgente dei dati della collection
|
188
|
-
-
|
189
|
-
|
190
|
-
|
213
|
+
- accept_nested_field => _accept_nested_field.html.erb
|
214
|
+
Questo partial renderizza una tabella per i campi associati al modello.
|
215
|
+
Più informazioni nelle note per il [nested attributes](#nested-attributes)
|
216
|
+
- Default/String => _base.html.erb
|
217
|
+
|
218
|
+
In futuro si prevede di aggiungere automatismi per renderizzare senza
|
191
219
|
l'intervento dell'utente dei campi.
|
192
220
|
- [OPTIONAL] Search Form:
|
193
221
|
Per poter aggiungere una form di ricerca basta aggiungere alla policy
|
@@ -203,22 +231,40 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
|
|
203
231
|
#...
|
204
232
|
```
|
205
233
|
|
234
|
+
### Nested Attributes
|
235
|
+
|
236
|
+
Il funzionamento si basa completamente sul sistema di NestedAttributes
|
237
|
+
di [Rails](https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html)
|
238
|
+
Note:
|
239
|
+
|
240
|
+
- Nelle policy bisogna definire come campo da editare il nome della relazione/nested_attribute
|
241
|
+
- Nella policy bisogna inoltre definire per i permitted_attributes anche il
|
242
|
+
`XXXXX_attributes => [Array attributi da editare] + [:id,:_destroy]`
|
243
|
+
- Il permitted _destroy vale solamente nel caso in cui si definisca nei nested_attributes che debba essere cancellabile.
|
244
|
+
- I campi visualizzati del modello sono presi dalla relativa policy.
|
245
|
+
|
246
|
+
Fai riferimento all'implementazione di esempio del dummy `Company->addresses`
|
247
|
+
|
206
248
|
### Translations
|
249
|
+
|
207
250
|
Traduzioni disponibili:
|
208
|
-
Per i bottoni della index, è possibile eseguire l'override del testo presente nel bottone.
|
251
|
+
Per i bottoni della index, è possibile eseguire l'override del testo presente nel bottone.
|
209
252
|
Leggere la documentazione nel file `app/helpers/base_editing_helper.rb#translate_with_controller_scoped`
|
210
253
|
|
211
|
-
|
212
254
|
## Testing helpers
|
213
255
|
|
214
256
|
### Requirements(installed with generators)
|
257
|
+
|
215
258
|
```ruby
|
216
259
|
group :test do
|
217
260
|
gem 'rails-controller-testing'
|
218
261
|
end
|
219
262
|
```
|
220
|
-
|
263
|
+
|
264
|
+
### Usage
|
265
|
+
|
221
266
|
Controllers:
|
267
|
+
|
222
268
|
```ruby
|
223
269
|
require 'rails_helper'
|
224
270
|
RSpec.describe "ServiceControllers", type: :request do
|
@@ -227,7 +273,9 @@ RSpec.describe "ServiceControllers", type: :request do
|
|
227
273
|
end
|
228
274
|
end
|
229
275
|
```
|
276
|
+
|
230
277
|
Model:
|
278
|
+
|
231
279
|
```ruby
|
232
280
|
require 'rails_helper'
|
233
281
|
RSpec.describe Service, type: :model do
|
@@ -236,7 +284,9 @@ RSpec.describe Service, type: :model do
|
|
236
284
|
ransack_permitted_associations: []
|
237
285
|
end
|
238
286
|
```
|
287
|
+
|
239
288
|
Policy
|
289
|
+
|
240
290
|
```ruby
|
241
291
|
require 'rails_helper'
|
242
292
|
##
|
@@ -262,10 +312,11 @@ end
|
|
262
312
|
```
|
263
313
|
|
264
314
|
## Message translations
|
315
|
+
|
265
316
|
I messaggi di generati per il flash provengono dal metodo BaseEditingBootstrap::ActionTranslation.human_action_message
|
266
317
|
e seguono una logica simile ad human_attribute_name.
|
267
318
|
Sono già presenti i messaggi di default, a cui viene passato il nome del modello,
|
268
|
-
ma è possibile fare override del messaggio con la classe:
|
319
|
+
ma è possibile fare override del messaggio con la classe:
|
269
320
|
|
270
321
|
```yaml
|
271
322
|
LANG:
|
@@ -279,22 +330,24 @@ LANG:
|
|
279
330
|
created: "customized %{model} created"
|
280
331
|
unsuccessful:
|
281
332
|
messages:
|
282
|
-
created:
|
333
|
+
created:
|
283
334
|
updated:
|
284
335
|
```
|
285
336
|
|
337
|
+
## Contributing
|
286
338
|
|
339
|
+
1. Setup env with:
|
287
340
|
|
288
|
-
## Contributing
|
289
|
-
1. Setup env with:
|
290
341
|
```shell
|
291
342
|
docker compose run app spec/dummy/bin/setup
|
292
343
|
```
|
293
344
|
|
294
|
-
2. Start environment with:
|
345
|
+
2. Start environment with:
|
346
|
+
|
295
347
|
```shell
|
296
348
|
docker compose up
|
297
349
|
```
|
298
350
|
|
299
351
|
## License
|
352
|
+
|
300
353
|
The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
|
@@ -24,14 +24,20 @@ module Utilities
|
|
24
24
|
type = :enum
|
25
25
|
generic_field = "enum"
|
26
26
|
elsif form.object.class.respond_to?(:reflect_on_association) &&
|
27
|
-
|
28
|
-
|
27
|
+
form.object.class.reflect_on_association(field.to_s).is_a?(ActiveRecord::Reflection::BelongsToReflection) &&
|
28
|
+
!form.object.class.reflect_on_association(field.to_s).polymorphic? # non deve essere polymorphic
|
29
29
|
# Abbiamo una relazione belongs_to da gestire
|
30
30
|
reflection = form.object.class.reflect_on_association(field.to_s)
|
31
31
|
type = :belongs_to
|
32
32
|
generic_field = "belongs_to_select"
|
33
33
|
locals[:relation_class] = reflection.klass
|
34
34
|
locals[:foreign_key] = reflection.foreign_key
|
35
|
+
elsif form.object.class.respond_to?(:nested_attributes_options) &&
|
36
|
+
form.object.class.nested_attributes_options.key?(field.to_sym)
|
37
|
+
type= :nested_attributes
|
38
|
+
generic_field = "accept_nested_field"
|
39
|
+
reflection = form.object.class.reflect_on_association(field.to_s)
|
40
|
+
locals[:new_object] = reflection.klass.new(reflection.foreign_key => form.object)
|
35
41
|
else
|
36
42
|
if form.object.class.respond_to?(:type_for_attribute)
|
37
43
|
type = form.object.class.type_for_attribute(field).type
|
@@ -1,13 +1,22 @@
|
|
1
1
|
module Utilities::PageHelper
|
2
2
|
include Utilities::IconHelper
|
3
|
+
|
4
|
+
##
|
5
|
+
# Traduzione del titolo EDIT con possibilità di modificare intestazione rispetto a modello
|
6
|
+
# - Il default è quello di Utilizzare la chiave .edit
|
7
|
+
# - Viene cercato la traduzione con la chiave titles.CHIAVE_I18N_MODELLO.edit
|
3
8
|
# @param [BaseModel] base_class
|
4
9
|
def title_mod_g(base_class)
|
5
|
-
"#{t("edit")} #{base_class.model_name.human}"
|
10
|
+
"#{t("titles.#{base_class.model_name.i18n_key}.edit", default: :edit)} #{base_class.model_name.human}"
|
6
11
|
end
|
7
12
|
|
13
|
+
##
|
14
|
+
# Traduzione del titolo NUOVO con possibilità di modificare intestazione rispetto a modello
|
15
|
+
# - Il default è quello di Utilizzare la chiave .new
|
16
|
+
# - Viene cercato la traduzione con la chiave titles.CHIAVE_I18N_MODELLO.new
|
8
17
|
# @param [BaseModel] base_class
|
9
18
|
def title_new_g(base_class)
|
10
|
-
"#{t("new")} #{base_class.model_name.human}"
|
19
|
+
"#{t("titles.#{base_class.model_name.i18n_key}.new", default: :new)} #{base_class.model_name.human}"
|
11
20
|
end
|
12
21
|
|
13
22
|
# Quando e se servirà verrà testato:
|
@@ -15,20 +15,34 @@ module Utilities::TemplateHelper
|
|
15
15
|
def find_template_with_fallbacks(obj, field, base_path, generic_field)
|
16
16
|
# nei casi in cui passiamo la classe e non l'oggetto, dobbiamo utilizzare un metodo interno a rails per
|
17
17
|
# avere la partial_path
|
18
|
+
|
19
|
+
obj_base_paths = []
|
20
|
+
# Primo livello in cui troviamo la partial path rispetto ad istanza o classe
|
18
21
|
partial_path = (obj.respond_to? :to_partial_path) ? obj.to_partial_path : obj._to_partial_path
|
19
|
-
|
22
|
+
obj_base_paths << "#{partial_path}/#{base_path}"
|
23
|
+
|
24
|
+
# Cerchiamo anche tutti i livelli di inheritance del modello
|
25
|
+
start_class = ((obj.respond_to? :to_partial_path) ? obj.class : obj).superclass
|
26
|
+
|
27
|
+
while start_class < ApplicationRecord
|
28
|
+
partial_path = start_class._to_partial_path
|
29
|
+
obj_base_paths << "#{partial_path}/#{base_path}"
|
30
|
+
start_class = start_class.superclass
|
31
|
+
end
|
20
32
|
|
21
33
|
[
|
22
34
|
# Precedenza modello e campo specifico
|
23
|
-
[field,
|
35
|
+
["Campo SPECIFICO + inheritance tra modelli", field, obj_base_paths],
|
24
36
|
# cerco tramite nome modello semplice, con namespace della risorsa (cell_field,header_field,form_field) e nome del campo specifico
|
25
|
-
["#{obj.model_name.element}/#{base_path}/#{field}", lookup_context.prefixes],
|
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],
|
26
40
|
# Ricerca tramite campo generico e prefissi di contesto che contiene anche controller e namespace di controller
|
27
|
-
["#{base_path}/#{generic_field}", lookup_context.prefixes],
|
28
|
-
[generic_field,
|
29
|
-
["base_editing/#{base_path}/#{generic_field}", []],
|
30
|
-
].each do |partial, prefixes|
|
31
|
-
Rails.logger.debug { "[BASE EDITING BOOTSTRAP]
|
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}" }
|
32
46
|
if lookup_context.exists?(partial, prefixes, true)
|
33
47
|
return lookup_context.find(partial, prefixes, true)
|
34
48
|
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
<tr class="nested-form-wrapper" data-new-record="<%= form.object.new_record? %>" id="<%= dom_id(form.object) %>">
|
2
|
+
|
3
|
+
<% policy(form.object).editable_attributes.each do |field| %>
|
4
|
+
<td>
|
5
|
+
<%= form_print_field(form, field) %>
|
6
|
+
<%= error_messages_for(form.object, field) %>
|
7
|
+
</td>
|
8
|
+
|
9
|
+
<% end %>
|
10
|
+
|
11
|
+
<td class="d-flex justify-content-end">
|
12
|
+
<button type="button" class="btn btn-outline-danger" data-action="nested-form#remove"><%= icon("trash") %></button>
|
13
|
+
<%= form.hidden_field :_destroy %>
|
14
|
+
</td>
|
15
|
+
|
16
|
+
</tr>
|
@@ -0,0 +1,48 @@
|
|
1
|
+
<%# locals: (form:, field:,new_object:) -%>
|
2
|
+
<%= content_tag :table, class: "table", data: {controller: 'nested-form'} do %>
|
3
|
+
|
4
|
+
<thead>
|
5
|
+
<tr>
|
6
|
+
<% policy(new_object).editable_attributes.each do |field| %>
|
7
|
+
<th>
|
8
|
+
<%= new_object.class.human_attribute_name(field) %>
|
9
|
+
</th>
|
10
|
+
<% end %>
|
11
|
+
<th class="text-end">
|
12
|
+
<button type="button" data-action="nested-form#add" class="btn btn-outline-success"><%= icon("plus-lg") %></button>
|
13
|
+
</th>
|
14
|
+
</tr>
|
15
|
+
</thead>
|
16
|
+
|
17
|
+
<template data-nested-form-target="template">
|
18
|
+
<%= form.fields_for field, new_object, child_index: 'NEW_RECORD' do |form_for_sections| %>
|
19
|
+
<%= render "nested_row_form", form: form_for_sections %>
|
20
|
+
<% end %>
|
21
|
+
</template>
|
22
|
+
|
23
|
+
<tbody>
|
24
|
+
|
25
|
+
<%= form.fields_for field do |form_for_sections| %>
|
26
|
+
<%= render "nested_row_form", form: form_for_sections %>
|
27
|
+
<% end %>
|
28
|
+
|
29
|
+
<!-- Inserted elements will be injected before that target. -->
|
30
|
+
<tr data-nested-form-target="target"></tr>
|
31
|
+
|
32
|
+
</tbody>
|
33
|
+
|
34
|
+
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<% if form.object.errors.key?(field) %>
|
38
|
+
|
39
|
+
<div class="row">
|
40
|
+
<div class="col-12">
|
41
|
+
<div class="alert alert-danger">
|
42
|
+
<%= form.object.errors[field].join(", ") %>
|
43
|
+
</div>
|
44
|
+
</div>
|
45
|
+
</div>
|
46
|
+
|
47
|
+
<% end %>
|
48
|
+
|
data/config/locales/it.yml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
1.
|
1
|
+
1.10.0
|
@@ -25,7 +25,7 @@ module BaseEditingBootstrap
|
|
25
25
|
if auth_object
|
26
26
|
Pundit.policy(auth_object, self.new).permitted_attributes_for_ransack.map(&:to_s)
|
27
27
|
else
|
28
|
-
Pundit.policy(
|
28
|
+
Pundit.policy(BaseEditingBootstrap.authentication_model.new, self.new).permitted_attributes_for_ransack.map(&:to_s)
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
@@ -33,7 +33,7 @@ module BaseEditingBootstrap
|
|
33
33
|
if auth_object
|
34
34
|
Pundit.policy(auth_object, self.new).permitted_associations_for_ransack.map(&:to_s)
|
35
35
|
else
|
36
|
-
Pundit.policy(
|
36
|
+
Pundit.policy(BaseEditingBootstrap.authentication_model.new, self.new).permitted_associations_for_ransack.map(&:to_s)
|
37
37
|
end
|
38
38
|
end
|
39
39
|
|
@@ -41,7 +41,7 @@ module BaseEditingBootstrap
|
|
41
41
|
if auth_object
|
42
42
|
Pundit.policy(auth_object, self.new).permitted_scopes_for_ransack.map(&:to_s)
|
43
43
|
else
|
44
|
-
Pundit.policy(
|
44
|
+
Pundit.policy(BaseEditingBootstrap.authentication_model.new, self.new).permitted_scopes_for_ransack.map(&:to_s)
|
45
45
|
end
|
46
46
|
end
|
47
47
|
end
|
@@ -26,7 +26,13 @@ module BaseEditingBootstrap::Forms
|
|
26
26
|
#
|
27
27
|
def form_style_class_for(method, options = {}, base_classes: ["form-control"])
|
28
28
|
classes = base_classes
|
29
|
-
|
29
|
+
if object.errors
|
30
|
+
classes << "is-invalid" if object.errors.include?(method)
|
31
|
+
# caso in cui il metodo è una relazione
|
32
|
+
if method.to_s.match(/(.*)_id\z/)
|
33
|
+
classes << "is-invalid" if object.errors.include?(Regexp.last_match(1))
|
34
|
+
end
|
35
|
+
end
|
30
36
|
classes << options[:class].split(" ") if options[:class]
|
31
37
|
classes.flatten.compact.uniq.join(" ")
|
32
38
|
end
|
@@ -47,7 +53,7 @@ module BaseEditingBootstrap::Forms
|
|
47
53
|
|
48
54
|
def select(method, choices = nil, options = {}, html_options = {}, &block)
|
49
55
|
html_options.merge!(class: form_style_class_for(method, html_options, base_classes: ["form-control", "form-select"]))
|
50
|
-
super(method, choices, options,html_options
|
56
|
+
super(method, choices, options, html_options, &block)
|
51
57
|
end
|
52
58
|
|
53
59
|
def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
|
@@ -0,0 +1,24 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'active_support/concern'
|
4
|
+
|
5
|
+
module BaseEditingBootstrap::GeneratorsHelpers
|
6
|
+
extend ActiveSupport::Concern
|
7
|
+
|
8
|
+
included do
|
9
|
+
|
10
|
+
private
|
11
|
+
def class_to_view_path(class_name)
|
12
|
+
base_path = ["app/views"]
|
13
|
+
|
14
|
+
base_path << class_name.deconstantize.then { |c| c.underscore.downcase }
|
15
|
+
singular_name = class_name.demodulize.underscore.downcase.singularize
|
16
|
+
base_path << singular_name.pluralize
|
17
|
+
base_path << singular_name
|
18
|
+
base_path.compact_blank!
|
19
|
+
end
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
@@ -36,8 +36,20 @@ module BaseEditingBootstrap
|
|
36
36
|
# possibili valori :edit , :index
|
37
37
|
config_accessor :after_success_create_redirect, default: :edit
|
38
38
|
|
39
|
+
##
|
40
|
+
# Classe che rappresenta l'utente, solitamente User
|
41
|
+
config_accessor :authentication_model_class, default: "User"
|
42
|
+
|
43
|
+
def self.authentication_model
|
44
|
+
self.authentication_model_class.constantize
|
45
|
+
end
|
46
|
+
|
47
|
+
##
|
48
|
+
# Factory per la creazione del modello che rappresenta l'auteticazione
|
49
|
+
config_accessor :authentication_model_factory, default: :user
|
50
|
+
|
39
51
|
def self.deprecator
|
40
|
-
@deprecator ||= ActiveSupport::Deprecation.new("
|
52
|
+
@deprecator ||= ActiveSupport::Deprecation.new("2.0", "BaseEditingBootstrap")
|
41
53
|
end
|
42
54
|
|
43
55
|
end
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module BaseEditingBootstrap
|
4
4
|
module Generators
|
5
5
|
class CellOverrideGenerator < ::Rails::Generators::Base
|
6
|
+
include BaseEditingBootstrap::GeneratorsHelpers
|
6
7
|
source_root File.expand_path("../../../../app/views/base_editing", __dir__)
|
7
8
|
argument :name, type: :string, banner: "Post", required: true
|
8
9
|
argument :attributes, type: :array, default: [], banner: "field field:type"
|
@@ -20,15 +21,15 @@ module BaseEditingBootstrap
|
|
20
21
|
if attributes.empty?
|
21
22
|
say "Need one field"
|
22
23
|
else
|
23
|
-
|
24
|
-
|
24
|
+
base_path = class_to_view_path(name)
|
25
|
+
|
25
26
|
attributes.each do |a|
|
26
27
|
attr_name, type = a.split(":")
|
27
28
|
|
28
29
|
type = :base if type.nil?
|
29
30
|
type = type.to_sym
|
30
31
|
raise "Type #{type} not found in #{TYPES}" unless TYPES.include?(type)
|
31
|
-
copy_file "cell_field/_#{type}.html.erb", File.join(
|
32
|
+
copy_file "cell_field/_#{type}.html.erb", File.join(*base_path, 'cell_field', "_#{attr_name}.html.erb")
|
32
33
|
end
|
33
34
|
end
|
34
35
|
|
@@ -3,6 +3,7 @@
|
|
3
3
|
module BaseEditingBootstrap
|
4
4
|
module Generators
|
5
5
|
class FieldOverrideGenerator < ::Rails::Generators::Base
|
6
|
+
include BaseEditingBootstrap::GeneratorsHelpers
|
6
7
|
source_root File.expand_path("../../../../app/views/base_editing", __dir__)
|
7
8
|
argument :name, type: :string, banner: "Post", required: true
|
8
9
|
argument :attributes, type: :array, default: [], banner: "field field:type"
|
@@ -20,15 +21,16 @@ module BaseEditingBootstrap
|
|
20
21
|
if attributes.empty?
|
21
22
|
say "Need one field"
|
22
23
|
else
|
23
|
-
|
24
|
-
|
24
|
+
|
25
|
+
base_path = class_to_view_path(name)
|
26
|
+
|
25
27
|
attributes.each do |a|
|
26
28
|
attr_name, type = a.split(":")
|
27
29
|
|
28
30
|
type = :base if type.nil?
|
29
31
|
type = type.to_sym
|
30
32
|
raise "Type #{type} not found in #{TYPES}" unless TYPES.include?(type)
|
31
|
-
copy_file "form_field/_#{type}.html.erb", File.join("
|
33
|
+
copy_file "form_field/_#{type}.html.erb", File.join(*base_path,"form_field", "_#{attr_name}.html.erb")
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -3,6 +3,8 @@
|
|
3
3
|
module BaseEditingBootstrap
|
4
4
|
module Generators
|
5
5
|
class HeaderOverrideGenerator < ::Rails::Generators::Base
|
6
|
+
include BaseEditingBootstrap::GeneratorsHelpers
|
7
|
+
|
6
8
|
source_root File.expand_path("../../../../app/views/base_editing", __dir__)
|
7
9
|
argument :name, type: :string, banner: "Post", required: true
|
8
10
|
argument :attributes, type: :array, default: [], banner: "field field:type"
|
@@ -20,15 +22,15 @@ module BaseEditingBootstrap
|
|
20
22
|
if attributes.empty?
|
21
23
|
say "Need one field"
|
22
24
|
else
|
23
|
-
|
24
|
-
|
25
|
+
base_path = class_to_view_path(name)
|
26
|
+
|
25
27
|
attributes.each do |a|
|
26
28
|
attr_name, type = a.split(":")
|
27
29
|
|
28
30
|
type = :base if type.nil?
|
29
31
|
type = type.to_sym
|
30
32
|
raise "Type #{type} not found in #{TYPES}" unless TYPES.include?(type)
|
31
|
-
copy_file "header_field/_#{type}.html.erb", File.join(
|
33
|
+
copy_file "header_field/_#{type}.html.erb", File.join(*base_path, 'header_field', "_#{attr_name}.html.erb")
|
32
34
|
end
|
33
35
|
end
|
34
36
|
|
@@ -30,6 +30,16 @@ module BaseEditingBootstrap
|
|
30
30
|
gem 'rails-controller-testing', group: :test, comment: "Required if used with controllers spec"
|
31
31
|
end
|
32
32
|
end
|
33
|
+
|
34
|
+
def install_nested_attributes_dependencies
|
35
|
+
# attualmente penso sia più sensato semplicemente scrivere a video i passaggi necessari, dato che
|
36
|
+
# potrebbe essere già presente importmap, nested_attribute_controller e le varie configurazioni
|
37
|
+
|
38
|
+
say "Install dependencies for nested attributes:"
|
39
|
+
say " bin/importmap pin @stimulus-components/rails-nested-form"
|
40
|
+
say "Attiva quindi come spiegato qua: https://www.stimulus-components.com/docs/stimulus-rails-nested-form il controller"
|
41
|
+
|
42
|
+
end
|
33
43
|
end
|
34
44
|
end
|
35
45
|
end
|
@@ -19,4 +19,12 @@ BaseEditingBootstrap.configure do |config|
|
|
19
19
|
# possibili valori :edit , :index
|
20
20
|
# config.after_success_create_redirect = :edit
|
21
21
|
|
22
|
+
##
|
23
|
+
# Classe che rappresenta l'utente, solitamente User
|
24
|
+
# config.authentication_model_class= "User"
|
25
|
+
|
26
|
+
##
|
27
|
+
# Factory per la creazione del modello che rappresenta l'auteticazione
|
28
|
+
# config.authentication_model_factory= :user
|
29
|
+
|
22
30
|
end
|
@@ -1,17 +1,33 @@
|
|
1
1
|
class <%= class_name %>Policy < BaseModelPolicy
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
def
|
3
|
+
<%- if attributes_names.size > 3 -%>
|
4
|
+
<%- ["permitted_attributes","editable_attributes","search_result_fields"].each do |meth| -%>
|
5
|
+
def <%= meth %>
|
6
|
+
[
|
7
|
+
<%- attributes_names.each do |m| -%>
|
8
|
+
:<%= m %>,
|
9
|
+
<%- end -%>
|
10
|
+
]
|
11
|
+
end
|
12
|
+
|
13
|
+
<%- end -%>
|
14
|
+
<%- else -%>
|
15
|
+
<%- ["permitted_attributes ","editable_attributes","search_result_fields"].each do |meth| -%>
|
16
|
+
def <%= meth %> = %i[<%= attributes_names.join(" ") %>]
|
17
|
+
<%- end -%>
|
18
|
+
<%- end -%>
|
6
19
|
<%- if @search_attrs.any? -%>
|
20
|
+
|
7
21
|
def search_fields
|
8
22
|
%i[<%= @search_attrs.join(" ") %>]
|
9
23
|
end
|
10
24
|
<%- end -%>
|
11
25
|
<%- if @permitted_attributes.any? -%>
|
26
|
+
|
12
27
|
# TODO check if correct with search_fields
|
13
28
|
def permitted_attributes_for_ransack
|
14
29
|
%i[<%= @permitted_attributes.join(" ") %>]
|
15
30
|
end
|
16
31
|
<%- end -%>
|
32
|
+
|
17
33
|
end
|
@@ -30,6 +30,8 @@ end
|
|
30
30
|
# :url_for_create
|
31
31
|
# :url_for_succ_delete
|
32
32
|
# :url_for_fail_delete
|
33
|
+
# :url_for_succ_create
|
34
|
+
# :url_for_succ_update
|
33
35
|
# :url_for_edit -> Rispetto agli altri questo risulta essere pià complicato in quanto
|
34
36
|
# deve ritornare una proc a cui passiamo il valore dell'istanza persistente
|
35
37
|
# che nei casi del after create non abbiamo a priori.
|
@@ -57,6 +59,27 @@ RSpec.shared_examples "base editing controller" do |factory: nil, only: [], exce
|
|
57
59
|
let(:url_for_create) { url_for(model.new) }
|
58
60
|
let(:url_for_succ_delete) { url_for(model) }
|
59
61
|
let(:url_for_fail_delete) { url_for_succ_delete }
|
62
|
+
|
63
|
+
let(:url_for_succ_create) {
|
64
|
+
case BaseEditingBootstrap.after_success_create_redirect
|
65
|
+
when :index
|
66
|
+
url_for_index
|
67
|
+
else
|
68
|
+
# edit
|
69
|
+
url_for_edit.call(assigns[:object])
|
70
|
+
end
|
71
|
+
}
|
72
|
+
|
73
|
+
let(:url_for_succ_update) {
|
74
|
+
case BaseEditingBootstrap.after_success_update_redirect
|
75
|
+
when :index
|
76
|
+
url_for_index
|
77
|
+
else
|
78
|
+
# edit
|
79
|
+
url_for_edit.call(assigns[:object])
|
80
|
+
end
|
81
|
+
}
|
82
|
+
|
60
83
|
let(:url_for_edit) { ->(p = persisted_instance) {
|
61
84
|
url_for([p, action: :edit])
|
62
85
|
} }
|
@@ -128,13 +151,7 @@ RSpec.shared_examples "base editing controller" do |factory: nil, only: [], exce
|
|
128
151
|
put url_for_update, params: {param_key => valid_attributes}
|
129
152
|
expect(assigns[:object]).to be_an_instance_of(model)
|
130
153
|
expect(response).to have_http_status(303)
|
131
|
-
|
132
|
-
when :index
|
133
|
-
expect(response).to redirect_to(url_for_index)
|
134
|
-
else
|
135
|
-
# edit
|
136
|
-
expect(response).to redirect_to(url_for_edit.call(assigns[:object]))
|
137
|
-
end
|
154
|
+
expect(response).to redirect_to(url_for_succ_update)
|
138
155
|
expect(flash.to_hash).to include("notice" => be_present)
|
139
156
|
end
|
140
157
|
|
@@ -153,13 +170,7 @@ RSpec.shared_examples "base editing controller" do |factory: nil, only: [], exce
|
|
153
170
|
post url_for_create, params: {param_key => valid_attributes}
|
154
171
|
expect(assigns[:object]).to be_an_instance_of(model)
|
155
172
|
expect(response).to have_http_status(303)
|
156
|
-
|
157
|
-
when :index
|
158
|
-
expect(response).to redirect_to(url_for_index)
|
159
|
-
else
|
160
|
-
# edit
|
161
|
-
expect(response).to redirect_to(url_for_edit.call(assigns[:object]))
|
162
|
-
end
|
173
|
+
expect(response).to redirect_to(url_for_succ_create)
|
163
174
|
expect(flash.to_hash).to include("notice" => be_present)
|
164
175
|
end
|
165
176
|
|
@@ -27,7 +27,7 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [],
|
|
27
27
|
|
28
28
|
##
|
29
29
|
# Oggetto solitamente di classe User che identifichi l'utente a cui eseguire il check dei permessi
|
30
|
-
let(:auth_object) {
|
30
|
+
let(:auth_object) { BaseEditingBootstrap.authentication_model }
|
31
31
|
let(:new_user_ransack_permitted_attributes) { ransack_permitted_attributes }
|
32
32
|
let(:new_user_ransack_permitted_associations) { ransack_permitted_associations }
|
33
33
|
let(:new_user_ransack_permitted_scopes) { ransack_permitted_scopes }
|
@@ -52,7 +52,7 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [],
|
|
52
52
|
|
53
53
|
let(:inner_auth_object) { nil }
|
54
54
|
it "new user" do
|
55
|
-
expect(Pundit).to receive(:policy).with(an_instance_of(
|
55
|
+
expect(Pundit).to receive(:policy).with(an_instance_of(BaseEditingBootstrap.authentication_model),
|
56
56
|
an_instance_of(described_class)).and_call_original
|
57
57
|
|
58
58
|
is_expected.to match_array(new_user_result)
|
@@ -13,6 +13,7 @@ module FactoryBot::Syntax::Methods
|
|
13
13
|
klass = FactoryBot::Internal.factory_by_name(args.first).build_class
|
14
14
|
|
15
15
|
klass.reflect_on_all_associations(:belongs_to).each do |r|
|
16
|
+
next if r.options.fetch(:optional, false)
|
16
17
|
association = FactoryBot.create(r.class_name.underscore)
|
17
18
|
attributes[:"#{r.name}_id"] = association.id
|
18
19
|
attributes[:"#{r.name}_type"] = association.class.name if r.options[:polymorphic]
|
@@ -14,7 +14,7 @@ RSpec::Matchers.define :permit_editable_attributes do |*expected_attributes|
|
|
14
14
|
end
|
15
15
|
|
16
16
|
RSpec.shared_examples "a standard base model policy" do |factory, check_default_responses: false|
|
17
|
-
let(:user) { create(
|
17
|
+
let(:user) { create(BaseEditingBootstrap.authentication_model_factory) }
|
18
18
|
let(:instance) { described_class.new(user, build(factory)) }
|
19
19
|
|
20
20
|
describe "response to all necessary methods" do
|
@@ -68,10 +68,10 @@ RSpec.shared_examples "a standard base model policy" do |factory, check_default_
|
|
68
68
|
end
|
69
69
|
end.flatten(1).compact.uniq
|
70
70
|
|
71
|
-
elenco_campi_ordinabili_in_relazione.each do |relation,field|
|
71
|
+
elenco_campi_ordinabili_in_relazione.each do |relation, field|
|
72
72
|
reflection = klass.reflect_on_association(relation.to_s)
|
73
73
|
policy = Pundit.policy(instance.user, reflection.class_name.constantize.new)
|
74
|
-
expect(policy.permitted_attributes_for_ransack.collect(&:to_sym).include?(field.to_sym)).to be_truthy, lambda{
|
74
|
+
expect(policy.permitted_attributes_for_ransack.collect(&:to_sym).include?(field.to_sym)).to be_truthy, lambda {
|
75
75
|
"Mi aspetto che `#{policy.class.name}#permitted_attributes_for_ransack` includa `#{field}` per permettere l'ordinamento del campo tramite relazione"
|
76
76
|
}
|
77
77
|
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.
|
4
|
+
version: 1.10.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-
|
11
|
+
date: 2025-09-12 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -350,6 +350,7 @@ files:
|
|
350
350
|
- app/views/base_editing/_index_main_buttons.html.erb
|
351
351
|
- app/views/base_editing/_index_title_header.html.erb
|
352
352
|
- app/views/base_editing/_navbar.html.erb
|
353
|
+
- app/views/base_editing/_nested_row_form.html.erb
|
353
354
|
- app/views/base_editing/_new_page_title_header.html.erb
|
354
355
|
- app/views/base_editing/_search.html.erb
|
355
356
|
- app/views/base_editing/_search_field.erb
|
@@ -363,6 +364,7 @@ files:
|
|
363
364
|
- app/views/base_editing/cell_field/_enum.html.erb
|
364
365
|
- app/views/base_editing/cell_field/_timestamps.html.erb
|
365
366
|
- app/views/base_editing/edit.html.erb
|
367
|
+
- app/views/base_editing/form_field/_accept_nested_field.html.erb
|
366
368
|
- app/views/base_editing/form_field/_base.html.erb
|
367
369
|
- app/views/base_editing/form_field/_belongs_to_select.html.erb
|
368
370
|
- app/views/base_editing/form_field/_boolean.html.erb
|
@@ -394,6 +396,7 @@ files:
|
|
394
396
|
- lib/base_editing_bootstrap/base_model.rb
|
395
397
|
- lib/base_editing_bootstrap/engine.rb
|
396
398
|
- lib/base_editing_bootstrap/forms/base.rb
|
399
|
+
- lib/base_editing_bootstrap/generators_helpers.rb
|
397
400
|
- lib/base_editing_bootstrap/is_validated.rb
|
398
401
|
- lib/base_editing_bootstrap/resource_finder.rb
|
399
402
|
- lib/base_editing_bootstrap/searches/base.rb
|