base_editing_bootstrap 1.3.2 → 1.5.0

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: 2e340e913487e9367deddd3f112c3a379af1ae132da18d27f19b44b6c4f133f6
4
- data.tar.gz: 35c0c82b8cc25665ddbeced4615baec2076ca3c6dc33651cc32d73b622d0b761
3
+ metadata.gz: e6bf71d45d64bd942a3891d528a28a6ef9b300c31e5764aa27a2c26bd58b64a8
4
+ data.tar.gz: f2d6638d9c2db49c57f91883a4be6dc7aa5e4232c64b4b98304c3233c61e02bb
5
5
  SHA512:
6
- metadata.gz: fca88f75c5a9e90adf8fc20a6cb46165745a90545649542f984b70b3dfb5b9310fbfaf11d9fc58debbde83022c46d8ab376b475ea64df88ac608f981e17fd567
7
- data.tar.gz: f7f4fe4e1755e174b980915ecd685754f68a9e5ea80cc258aa31c50325c16c709448992e2a3b28a64808d09ddbbff2d0a673e6446f9470b09409614f751921e2
6
+ metadata.gz: 0b552e2dbb6d71861e4a073ee49a11cdceb3612ced84b4320661583e6c468020c17b8392790b7e87dfd7f0e8b05f7c94e4565b18921a43d0763e68b34da960e1
7
+ data.tar.gz: 351b8dd26cbaa739e9010d9b24d2721e554b7fdd3f478c5e5bce75717097fcc5ae377b26fadcbfec25b6d5d57b614f5881918a5f6148462fa4deb6a8f32f5fd0
data/CHANGELOG.md CHANGED
@@ -2,6 +2,25 @@
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.5.0 - 2025-01-16
6
+ #### Documentation
7
+ - Update documentation - (3a29e34) - Marino Bonetti
8
+ #### Features
9
+ - Render enum in index - (c520cd1) - Marino Bonetti
10
+ - Belongs_to Form fields - (6572b9f) - Marino Bonetti
11
+ #### Refactoring
12
+ - Estrapolazione policy in metodo - (711746b) - Marino Bonetti
13
+
14
+ - - -
15
+
16
+ ## 1.4.0 - 2025-01-13
17
+ #### Bug Fixes
18
+ - Correct generator for values - (a83f07a) - Marino Bonetti
19
+ #### Features
20
+ - Has one attached automatic file_field - (fd32678) - Marino Bonetti
21
+
22
+ - - -
23
+
5
24
  ## 1.3.2 - 2025-01-10
6
25
  #### Bug Fixes
7
26
  - Fields in form inside layout - (a2e1d42) - Marino Bonetti
data/README.md CHANGED
@@ -25,6 +25,8 @@ Then run installer:
25
25
  $ bundle exec rails g base_editing_bootstrap:install
26
26
  ```
27
27
 
28
+ **Si presume quindi che ActiveStorage sia correttamente installato, completo del javascript per il direct upload**
29
+
28
30
  ### Generators
29
31
  Then Install dependency (if you run base_editing_bootstrap:install you are good to go):
30
32
  ```bash
@@ -143,7 +145,20 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
143
145
  **Cell Field**:
144
146
  - created_at => timestamps.html.erb
145
147
  - updated_at => timestamps.html.erb
148
+ - Enum => _enum.html.erb
149
+ Per gli enum, le traduzioni dei labels di ogni valore provengono da i18n
150
+ attraverso l'helper: `Utilities::EnumHelper#enum_translation` con variant `:cell_field`
151
+ il quale sfrutta human_attribute_name del modello con 'attributo.enum_value',
152
+ quindi ad esempio per un modello `Post` con enum `categoria` e un enum `importante`, la ricerca nelle traduzioni
153
+ saranno così composte:
154
+ - it.activerecord.attributes.post/categoria.importante_cell_field
155
+ - it.activerecord.attributes.categoria.importante_cell_field
156
+ - it.attributes.importante_cell_field
157
+ - it.activerecord.attributes.post/categoria.importante
158
+ - it.activerecord.attributes.categoria.importante
159
+ - it.attributes.importante => nil
146
160
  - default => base.html.erb
161
+
147
162
  **Form Field**
148
163
  - Integer => _integer.html.erb
149
164
  - Float => _decimal.html.erb
@@ -152,9 +167,23 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
152
167
  - Date => _date.html.erb
153
168
  - Boolean => _boolean.html.erb
154
169
  - Enum => _enum.html.erb
155
- Per gli enum, le traduzioni dei labels di ogni valore provvengono da i18n
156
- attraverso l'helper: `Utilities::EnumHelper#enum_translation`
157
- il quale utilizza il nome dell'attributo con
170
+ Per gli enum, le traduzioni dei labels di ogni valore provengono da i18n
171
+ attraverso l'helper: `Utilities::EnumHelper#enum_translation`" con variante `:form_field`
172
+ il quale sfrutta human_attribute_name del modello con 'attributo.enum_value',
173
+ quindi ad esempio per un modello `Post` con enum `categoria` e un enum `importante`, la ricerca nelle traduzioni
174
+ saranno così composte:
175
+ - it.activerecord.attributes.post/categoria.importante_form_field
176
+ - it.activerecord.attributes.categoria.importante_form_field
177
+ - it.attributes.importante_form_field
178
+ - it.activerecord.attributes.post/categoria.importante
179
+ - it.activerecord.attributes.categoria.importante
180
+ - it.attributes.importante => nil
181
+ - belongs_to => _belongs_to_select.html.erb
182
+ Come si può leggere dal partial, il modello che viene utilizzato come base dati per la collection deve
183
+ avere come metodo `option_label` che deve ritornare la label da utilizzare nelle options.
184
+ Di default questo metodo utilizza il semplice #to_s
185
+ Ha anche un metodo per il valore da utilizzare come chiave, di default viene dedotto dalla reflection
186
+ come anche il nome della classe da utilizzare come sorgente dei dati della collection
158
187
  - Default/String => _base.html.erb
159
188
 
160
189
  In futuro si prevede di aggiungere automatismi per renderizzare senza
@@ -2,6 +2,8 @@ module Utilities
2
2
  module FormHelper
3
3
  include TemplateHelper
4
4
  include EnumHelper
5
+ include IconHelper
6
+ include Pundit::Authorization
5
7
  ##
6
8
  # Metodo su cui eseguire override per i campi specifici rispetto all'oggetto gestito dal controller
7
9
  # @deprecated Utilizza form_print_field(form, field) senza sovrascriverlo
@@ -19,13 +21,28 @@ module Utilities
19
21
  def form_print_field(form, field)
20
22
  locals = {form:, field:}
21
23
  if form.object.class.respond_to?(:defined_enums) && form.object.class.defined_enums.key?(field.to_s)
24
+ type = :enum
22
25
  generic_field = "enum"
26
+ elsif form.object.class.respond_to?(:reflect_on_association) &&
27
+ form.object.class.reflect_on_association(field.to_s).is_a?(ActiveRecord::Reflection::BelongsToReflection)
28
+ # Abbiamo una relazione belongs_to da gestire
29
+ reflection = form.object.class.reflect_on_association(field.to_s)
30
+ type = :belongs_to
31
+ generic_field = "belongs_to_select"
32
+ locals[:relation_class] = reflection.klass
33
+ locals[:foreign_key] = reflection.foreign_key
23
34
  else
24
35
  if form.object.class.respond_to?(:type_for_attribute)
25
36
  type = form.object.class.type_for_attribute(field).type
37
+
38
+ # Se non abbiamo ancora il type tentiamo di capire se è di tipo attachment SINGOLO
39
+ if type.nil? and form.object.respond_to?(:"#{field}_attachment")
40
+ type = :has_one_attachment
41
+ end
26
42
  else
27
43
  type = :string
28
44
  end
45
+
29
46
  case type
30
47
  when :datetime
31
48
  generic_field = "datetime"
@@ -41,6 +58,8 @@ module Utilities
41
58
  generic_field = "integer"
42
59
  when :boolean
43
60
  generic_field = "boolean"
61
+ when :has_one_attachment
62
+ generic_field = "has_one_attachment"
44
63
  else
45
64
  generic_field = "base"
46
65
  end
@@ -3,6 +3,7 @@ module Utilities
3
3
  include TemplateHelper
4
4
  include PageHelper
5
5
  include IconHelper
6
+ include EnumHelper
6
7
 
7
8
  ##
8
9
  # Per aggiungere bottoni:
@@ -71,10 +72,16 @@ module Utilities
71
72
  when :created_at, :updated_at
72
73
  "timestamps"
73
74
  else
74
- type = klazz.type_for_attribute(field).type
75
+ if klazz.respond_to?(:defined_enums) && klazz.defined_enums.key?(field.to_s)
76
+ type = :enum
77
+ else
78
+ type = klazz.type_for_attribute(field).type
79
+ end
75
80
  case type
76
81
  when :boolean
77
82
  "boolean"
83
+ when :enum
84
+ "enum"
78
85
  else
79
86
  "base"
80
87
  end
@@ -30,3 +30,5 @@
30
30
  <%= error_messages_for(form.object, form_field) %>
31
31
  <% end %>
32
32
  <%= render partial: "editing_form_help_text", locals: {object: form.object, field: form_field} %>
33
+ <%= content_for :form_field_ending %>
34
+ <% content_for :form_field_ending, "", flush: true #RESET altrimenti ce lo troviamo nel successivo campo %>
@@ -0,0 +1,3 @@
1
+ <%# Renderizza il campo nella tabella della pagina dei risultati %>
2
+ <%# locals: (obj:,field:) -%>
3
+ <td><%= enum_translation(obj.class, field, obj.send(field), :cell_field) %></td>
@@ -0,0 +1,6 @@
1
+ <%# locals: (form:, field:,relation_class:,foreign_key:,value_method: :id, label_method: :option_label) -%>
2
+ <%= form.select(foreign_key, options_from_collection_for_select(policy_scope(relation_class),
3
+ value_method, label_method,
4
+ selected: form.object.send(foreign_key)),
5
+ include_blank: true
6
+ ) %>
@@ -1,2 +1,2 @@
1
1
  <%# locals: (form:, field:) -%>
2
- <%= form.select(field, enum_collection(form.object.class, field)) %>
2
+ <%= form.select(field, enum_collection(form.object.class, field, :form_field)) %>
@@ -0,0 +1,31 @@
1
+ <%# locals: (form:, field:) -%>
2
+ <%
3
+ is_attached = form.object.send(field).attached?
4
+ hidden_field_id = dom_id(form.object, "hidden_#{field}")
5
+ preview_image_id = dom_id(form.object, "preview_image_#{field}")
6
+ filename_id = dom_id(form.object, "filename_#{field}")
7
+
8
+ javascript_clear_event = <<~JAVASCRIPT
9
+ try{document.getElementById('#{hidden_field_id}').value = ''}catch{};
10
+ try{document.getElementById('#{preview_image_id}').remove()}catch{};
11
+ try{document.getElementById('#{filename_id}').remove()}catch{};
12
+ return false
13
+ JAVASCRIPT
14
+
15
+ %>
16
+ <%= form.hidden_field field, value: form.object.send(field).signed_id, id: hidden_field_id if is_attached %>
17
+
18
+ <%= form.file_field field, direct_upload: true %>
19
+
20
+ <% if is_attached %>
21
+ <%= content_tag :span, form.object.send(field).attachment.blob.filename, class: "input-group-text", id: filename_id %>
22
+ <%= content_tag :button, icon(:trash),
23
+ onclick: javascript_clear_event,
24
+ class: "btn btn-outline-secondary rounded-0" %>
25
+ <%= link_to icon(:download), form.object.send(field), class: "btn btn-outline-secondary", target: :_blank %>
26
+ <% if form.object.send(field).representable? %>
27
+ <% content_for :form_field_ending,flush:true do %>
28
+ <%= content_tag :div, image_tag(form.object.send(field).representation(resize_to_limit: [100, 100])), id: preview_image_id %>
29
+ <% end %>
30
+ <% end %>
31
+ <% end %>
@@ -43,7 +43,9 @@ Gem::Specification.new do |spec|
43
43
  spec.add_development_dependency 'faker', '~> 3.3'
44
44
  spec.add_development_dependency "puma", '~> 6.4'
45
45
  spec.add_development_dependency "sqlite3"
46
- spec.add_development_dependency "sprockets-rails", '~> 3.4'
46
+ spec.add_development_dependency "propshaft", '~> 1.1.0'
47
+ spec.add_development_dependency 'importmap-rails', '~> 2.1.0'
48
+ spec.add_development_dependency "image_processing", "~> 1.2"
47
49
  spec.add_development_dependency 'rails-i18n'
48
50
  spec.add_development_dependency "i18n-debug", '~> 1.2'
49
51
  spec.add_development_dependency "cssbundling-rails", '~> 1.4'
@@ -1 +1 @@
1
- 1.3.2
1
+ 1.5.0
@@ -8,6 +8,14 @@ module BaseEditingBootstrap
8
8
  include IsValidated
9
9
  include ActionTranslation
10
10
  delegate :ransackable_attributes, :ransackable_associations, to: :@class
11
+
12
+
13
+ ##
14
+ # Label da utilizzare nelle option per quando si genera le select dei belongs to
15
+ # @return [String,NilClass]
16
+ def option_label
17
+ to_s
18
+ end
11
19
  end
12
20
 
13
21
  class_methods do
@@ -37,21 +37,27 @@ module BaseEditingBootstrap::Searches
37
37
  end
38
38
 
39
39
  def search_fields
40
- Pundit.policy(@user, @model_klass).search_fields.collect { |f| Field.new(self, f) }
40
+ policy.search_fields.collect { |f| Field.new(self, f) }
41
41
  end
42
42
 
43
43
  def search_result_fields
44
- Pundit.policy(@user, @model_klass).search_result_fields
44
+ policy.search_result_fields
45
45
  end
46
46
 
47
47
  ##
48
48
  # Ritorna se il campo deve essere ordinabile o meno
49
49
  def sortable?(field)
50
- Pundit.policy(@user, @model_klass).sortable_search_result_fields.include?(field)
50
+ policy.sortable_search_result_fields.include?(field)
51
51
  end
52
52
 
53
53
  def persisted?
54
54
  false
55
55
  end
56
+
57
+ ##
58
+ # @return [ApplicationPolicy]
59
+ def policy
60
+ Pundit.policy(@user, @model_klass)
61
+ end
56
62
  end
57
63
  end
@@ -1,8 +1,8 @@
1
1
  class <%= class_name %>Policy < BaseModelPolicy
2
2
 
3
- def editable_attributes = %w[<%= attributes_names.join(" ") %>]
4
- def permitted_attributes = %w[<%= attributes_names.join(" ") %>]
5
- def search_result_fields = %w[<%= attributes_names.join(" ") %>]
3
+ def editable_attributes = %i[<%= attributes_names.join(" ") %>]
4
+ def permitted_attributes = %i[<%= attributes_names.join(" ") %>]
5
+ def search_result_fields = %i[<%= attributes_names.join(" ") %>]
6
6
  <%- if @search_attrs.any? -%>
7
7
  def search_fields
8
8
  %i[<%= @search_attrs.join(" ") %>]
@@ -11,7 +11,7 @@ class <%= class_name %>Policy < BaseModelPolicy
11
11
  <%- if @permitted_attributes.any? -%>
12
12
  # TODO check if correct with search_fields
13
13
  def permitted_attributes_for_ransack
14
- %w[<%= @permitted_attributes.join(" ") %>]
14
+ %i[<%= @permitted_attributes.join(" ") %>]
15
15
  end
16
16
  <%- end -%>
17
17
  end
@@ -1,4 +1,4 @@
1
- RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [], ransack_permitted_associations: []|
1
+ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [], ransack_permitted_associations: [], option_label_method: :to_s|
2
2
 
3
3
  it_behaves_like "a validated? object"
4
4
 
@@ -6,6 +6,14 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [], ransa
6
6
  expect(described_class).to respond_to(:human_action_message)
7
7
  end
8
8
 
9
+ it "have method for belongs_to options" do
10
+ instance = described_class.new
11
+ expect(instance).to respond_to(:option_label)
12
+
13
+ expect(instance).to receive(option_label_method).and_call_original
14
+ instance.option_label
15
+ end
16
+
9
17
  ##
10
18
  # Oggetto solitamente di classe User che identifichi l'utente a cui eseguire il check dei permessi
11
19
  let(:auth_object) { :auth_object }
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.3.2
4
+ version: 1.5.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-01-10 00:00:00.000000000 Z
11
+ date: 2025-01-16 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -175,19 +175,47 @@ dependencies:
175
175
  - !ruby/object:Gem::Version
176
176
  version: '0'
177
177
  - !ruby/object:Gem::Dependency
178
- name: sprockets-rails
178
+ name: propshaft
179
179
  requirement: !ruby/object:Gem::Requirement
180
180
  requirements:
181
181
  - - "~>"
182
182
  - !ruby/object:Gem::Version
183
- version: '3.4'
183
+ version: 1.1.0
184
184
  type: :development
185
185
  prerelease: false
186
186
  version_requirements: !ruby/object:Gem::Requirement
187
187
  requirements:
188
188
  - - "~>"
189
189
  - !ruby/object:Gem::Version
190
- version: '3.4'
190
+ version: 1.1.0
191
+ - !ruby/object:Gem::Dependency
192
+ name: importmap-rails
193
+ requirement: !ruby/object:Gem::Requirement
194
+ requirements:
195
+ - - "~>"
196
+ - !ruby/object:Gem::Version
197
+ version: 2.1.0
198
+ type: :development
199
+ prerelease: false
200
+ version_requirements: !ruby/object:Gem::Requirement
201
+ requirements:
202
+ - - "~>"
203
+ - !ruby/object:Gem::Version
204
+ version: 2.1.0
205
+ - !ruby/object:Gem::Dependency
206
+ name: image_processing
207
+ requirement: !ruby/object:Gem::Requirement
208
+ requirements:
209
+ - - "~>"
210
+ - !ruby/object:Gem::Version
211
+ version: '1.2'
212
+ type: :development
213
+ prerelease: false
214
+ version_requirements: !ruby/object:Gem::Requirement
215
+ requirements:
216
+ - - "~>"
217
+ - !ruby/object:Gem::Version
218
+ version: '1.2'
191
219
  - !ruby/object:Gem::Dependency
192
220
  name: rails-i18n
193
221
  requirement: !ruby/object:Gem::Requirement
@@ -335,14 +363,17 @@ files:
335
363
  - app/views/base_editing/_tabs.html.erb
336
364
  - app/views/base_editing/cell_field/_base.html.erb
337
365
  - app/views/base_editing/cell_field/_boolean.html.erb
366
+ - app/views/base_editing/cell_field/_enum.html.erb
338
367
  - app/views/base_editing/cell_field/_timestamps.html.erb
339
368
  - app/views/base_editing/edit.html.erb
340
369
  - app/views/base_editing/form_field/_base.html.erb
370
+ - app/views/base_editing/form_field/_belongs_to_select.html.erb
341
371
  - app/views/base_editing/form_field/_boolean.html.erb
342
372
  - app/views/base_editing/form_field/_date.html.erb
343
373
  - app/views/base_editing/form_field/_datetime.html.erb
344
374
  - app/views/base_editing/form_field/_decimal.html.erb
345
375
  - app/views/base_editing/form_field/_enum.html.erb
376
+ - app/views/base_editing/form_field/_has_one_attachment.html.erb
346
377
  - app/views/base_editing/form_field/_integer.html.erb
347
378
  - app/views/base_editing/header_field/_base.html.erb
348
379
  - app/views/base_editing/index.html.erb