base_editing_bootstrap 1.10.0 → 1.12.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: 489e2ffcb61b916547f555b4b80a90e9d542c0738afb83dd104418e29865a542
4
- data.tar.gz: 3f7cba0e07451401983eeef463ff0a18ad97f2aee1a5c16a836980d4e77e4ca3
3
+ metadata.gz: 220d6cba364a9462e61d4db63e648b902899d92330afe32fa7f9844f898e5793
4
+ data.tar.gz: d74f68c4b7d6682b85dcde6089c41ec23a00596e848c6d7c98bcac89e14c5f67
5
5
  SHA512:
6
- metadata.gz: 2e62893f671fe1ef62e0c9fe52cef3c104fdab7646bb1a03b774ae9d9c5650f288e7329b5e4c5e29fda3f935c0e3706a1af8ecb90b220a16fa1f6f5e8759e726
7
- data.tar.gz: 52055575f2459020e2963d8af95da7c904c3301cf8c4127685a1529f062ab884d9fa77fe59b22b3ff20234e23b5ee0d5db84ae9cfc472cda58ea7748cf63ec9c
6
+ metadata.gz: 3b64e2d71bbed18776836d07c93dc771e33bf43d3cc465cd3b88839936ea6694f8763f928178764e5b30625416a2f83cabba59a40e879249299d52ba397f862f
7
+ data.tar.gz: cc362577fa363200349af2ee2b2cb076573047d865f5b9866434c213518e1a3471b0b6dcae851d59650f5b9bb973a0bab7093dce729e45d4783147bbc68305fc
data/CHANGELOG.md CHANGED
@@ -2,6 +2,32 @@
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.12.0 - 2025-12-05
6
+ #### Features
7
+ - Add Capacity of custom disable action column - (4910fc3) - Marino Bonetti
8
+ #### Bug Fixes
9
+ - Add ability to override new_button classes - (ba18b10) - Marino Bonetti
10
+ #### Documentation
11
+ - Update generator example - (445bf2f) - Marino Bonetti
12
+ - Update README with ransack sorting, distinct, and action column examples - (5b9728b) - Marino Bonetti
13
+ #### Tests
14
+ - Add option to define option_label_instance in shared example - (5e7628b) - Marino Bonetti
15
+ - Add Check for action columns - (001b0c9) - Marino Bonetti
16
+ #### Continuous Integration
17
+ - Add Rails 8.1 to Matrix - (455ffc6) - Marino Bonetti
18
+ #### Miscellaneous Chores
19
+ - Extend rails compatibility - (ef018b0) - Marino Bonetti
20
+
21
+ - - -
22
+
23
+ ## 1.11.0 - 2025-09-15
24
+ #### Bug Fixes
25
+ - Simplify gem push command in cog.toml - (ab70061) - Marino Bonetti
26
+ #### Features
27
+ - Add nested_attributes for has_one - (d76422c) - Marino Bonetti
28
+
29
+ - - -
30
+
5
31
  ## 1.10.0 - 2025-09-12
6
32
  #### Features
7
33
  - Automatic Nested attributes - (dad38de) - Marino Bonetti
data/README.md CHANGED
@@ -114,8 +114,19 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
114
114
  ```ruby
115
115
  class PostsController < BaseEditingController
116
116
  ##
117
- # Set default sort order for ransack
117
+ # Configure default sort in the index query.
118
+ # Works like documented in https://activerecord-hackery.github.io/ransack/getting-started/sorting/#sorting-in-the-controller
118
119
  # self.default_sorts= ["id"]
120
+
121
+ ##
122
+ # Configure default distinct results in the index query.
123
+ # Works like documented in https://activerecord-hackery.github.io/ransack/going-further/other-notes/#problem-with-distinct-selects
124
+ # self.default_distinct=true
125
+
126
+ ##
127
+ # Display action column in the index table.
128
+ # self.display_action_column = true
129
+
119
130
  end
120
131
  ```
121
132
  - Aggiungere la rotta: `resources :posts`
@@ -210,9 +221,13 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
210
221
  Di default questo metodo utilizza il semplice #to_s
211
222
  Ha anche un metodo per il valore da utilizzare come chiave, di default viene dedotto dalla reflection
212
223
  come anche il nome della classe da utilizzare come sorgente dei dati della collection
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)
224
+ - accept_nested_attributes
225
+ - has_many => _accept_has_many_nested_field.html.erb
226
+ Questo partial renderizza una tabella per i campi associati al modello.
227
+ Più informazioni nelle note per il [nested attributes](#nested-attributes)
228
+ - has_one => _accept_has_one_nested_field.html.erb
229
+ Questo partial renderizza una nested form che si comporta come una form normale renderizzando i vari campi del
230
+ nested attraverso quanto elencato nella policy dell'oggetto padre.
216
231
  - Default/String => _base.html.erb
217
232
 
218
233
  In futuro si prevede di aggiungere automatismi per renderizzare senza
@@ -238,8 +253,9 @@ di [Rails](https://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/Cla
238
253
  Note:
239
254
 
240
255
  - 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]`
256
+ - Nella policy bisogna inoltre definire per i permitted_attributes anche:
257
+ - nel caso di has_many: `XXXXX_attributes => [Array attributi da editare] + [:id,:_destroy]`
258
+ - nel caso di has_one: `XXXXX_attributes => [Array attributi da editare]`
243
259
  - Il permitted _destroy vale solamente nel caso in cui si definisca nei nested_attributes che debba essere cancellabile.
244
260
  - I campi visualizzati del modello sono presi dalla relativa policy.
245
261
 
@@ -19,15 +19,20 @@ class BaseEditingController < RestrictedAreaController
19
19
  # Works like documented in https://activerecord-hackery.github.io/ransack/going-further/other-notes/#problem-with-distinct-selects
20
20
  class_attribute :default_distinct, default: true
21
21
 
22
+ ##
23
+ # Display action column in the index table.
24
+ class_attribute :display_action_column, default: true
25
+
22
26
  def index
23
- #se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
27
+ # se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
24
28
  authorize base_class unless pundit_policy_authorized?
25
29
 
26
30
  q = policy_scope(base_scope)
27
31
  @search_instance = search_class.new(q, current_user,
28
32
  params: params.permit(:page, :q => {}), # FIXME trovare modo per essere più "STRONG"
29
33
  sorts: default_sorts,
30
- distinct: default_distinct
34
+ distinct: default_distinct,
35
+ display_action_column: display_action_column
31
36
  )
32
37
  @search_instance = yield(@search_instance) if block_given?
33
38
  end
@@ -36,7 +41,7 @@ class BaseEditingController < RestrictedAreaController
36
41
  @object = base_class.new
37
42
  @object = yield(@object) if block_given?
38
43
 
39
- #se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
44
+ # se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
40
45
  authorize @object unless pundit_policy_authorized?
41
46
 
42
47
  respond_to do |format|
@@ -67,7 +72,7 @@ class BaseEditingController < RestrictedAreaController
67
72
  def create
68
73
  @object = base_class.new(permitted_attributes)
69
74
  @object = yield(@object) if block_given?
70
- #se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
75
+ # se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
71
76
  authorize @object unless pundit_policy_authorized?
72
77
 
73
78
  respond_to do |format|
@@ -129,7 +134,7 @@ class BaseEditingController < RestrictedAreaController
129
134
  def load_object
130
135
  @object = base_class.find(params[:id])
131
136
 
132
- #se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
137
+ # se è già stato autorizzano non rieseguiamo, utile nel caso vogliamo sovrascrivere la logica di autorizzazione in inheritance
133
138
  authorize @object unless pundit_policy_authorized?
134
139
  logger.debug { "Oggetto #{@object.inspect}" }
135
140
  end
@@ -34,10 +34,18 @@ module Utilities
34
34
  locals[:foreign_key] = reflection.foreign_key
35
35
  elsif form.object.class.respond_to?(:nested_attributes_options) &&
36
36
  form.object.class.nested_attributes_options.key?(field.to_sym)
37
- type= :nested_attributes
38
- generic_field = "accept_nested_field"
37
+ type = :nested_attributes
39
38
  reflection = form.object.class.reflect_on_association(field.to_s)
40
- locals[:new_object] = reflection.klass.new(reflection.foreign_key => form.object)
39
+ case reflection
40
+ when ActiveRecord::Reflection::HasManyReflection
41
+ locals[:new_object] = reflection.klass.new(reflection.foreign_key => form.object)
42
+ generic_field = "accept_has_many_nested_field"
43
+ when ActiveRecord::Reflection::HasOneReflection
44
+ form.object.send(:"build_#{field}") unless form.object.send(field).present?
45
+ generic_field = "accept_has_one_nested_field"
46
+ else
47
+ raise "Unknown reflection for nested attributes #{field}->#{reflection.class}"
48
+ end
41
49
  else
42
50
  if form.object.class.respond_to?(:type_for_attribute)
43
51
  type = form.object.class.type_for_attribute(field).type
@@ -49,8 +49,7 @@ module Utilities::PageHelper
49
49
  # @param [String] path
50
50
  # @param [Hash] options
51
51
  def new_button(path, options = {})
52
- options.merge!({class: 'btn btn-success btn-sm'})
53
- link_to icon("plus-lg", I18n.t(:new)), path, options
52
+ link_to icon("plus-lg", I18n.t(:new)), path, options.reverse_merge({class: 'btn btn-success btn-sm'})
54
53
  end
55
54
 
56
55
  # @param [BaseModel] obj instance
@@ -1,15 +1,7 @@
1
1
  <%= render layout: "form_container" do %>
2
2
  <%= form_for @object, builder: form_builder do |form| %>
3
3
 
4
- <%= render layout: "form_body_container" do %>
5
- <%= render partial: "form_field_header", locals: {form:} %>
6
- <%= render partial: "form_base_errors", locals: {form:} if form.object.errors.key?(:base) %>
7
- <%= render layout: "form_fields_container" do %>
8
- <%= render collection: form_attributes(form.object),
9
- layout: "form_field_container",
10
- partial: "form_field", locals: {form:} %>
11
- <% end %>
12
- <% end %>
4
+ <%= render partial: "form_full_components", locals: {form: form} %>
13
5
 
14
6
  <%= render layout: "form_footer_container" do %>
15
7
  <%= render partial: "form_footer", locals: {form: form} %>
@@ -0,0 +1,14 @@
1
+ <%#
2
+ Questo partial è il raggruppamento di tutti gli elementi tranne il footer del form.
3
+ Serve per riutilizzarlo anche nel nested attributes come base per costruire tutti gli elementi
4
+ %>
5
+ <%# locals: (form:) -%>
6
+ <%= render layout: "form_body_container" do %>
7
+ <%= render partial: "form_field_header", locals: {form:} %>
8
+ <%= render partial: "form_base_errors", locals: {form:} if form.object.errors.key?(:base) %>
9
+ <%= render layout: "form_fields_container" do %>
10
+ <%= render collection: form_attributes(form.object),
11
+ layout: "form_field_container",
12
+ partial: "form_field", locals: {form:} %>
13
+ <% end %>
14
+ <% end %>
@@ -1,10 +1,10 @@
1
- <table class="table table-head-fixed text-nowrap <%= dom_class(@search_instance.model_klass,:search_results) %>">
1
+ <table class="table table-head-fixed text-nowrap <%= dom_class(@search_instance.model_klass, :search_results) %>">
2
2
  <thead>
3
3
  <tr>
4
4
  <% @search_instance.search_result_fields.each do |srf| %>
5
5
  <%= render_header_cell_field(@search_instance, srf) %>
6
6
  <% end %>
7
- <th class="action_col"></th>
7
+ <%= content_tag :th, nil, class: "action_col" if @search_instance.display_action_column %>
8
8
  </tr>
9
9
  </thead>
10
10
  <tbody>
@@ -2,7 +2,9 @@
2
2
  <% @search_instance.search_result_fields.each do |srf| %>
3
3
  <%= render_cell_field(obj, srf) %>
4
4
  <% end %>
5
- <td>
6
- <%= render partial: "search_result_buttons", locals: {obj:} %>
7
- </td>
5
+ <% if @search_instance.display_action_column %>
6
+ <td class="action_col">
7
+ <%= render partial: "search_result_buttons", locals: {obj:} %>
8
+ </td>
9
+ <% end %>
8
10
  </tr>
@@ -0,0 +1,4 @@
1
+ <%# locals: (form:, field:) -%>
2
+ <%= form.fields_for field do |form_for_sections| %>
3
+ <%= render partial: "form_full_components", locals: {form: form_for_sections} %>
4
+ <% end %>
@@ -29,7 +29,7 @@ Gem::Specification.new do |spec|
29
29
  end
30
30
  spec.files += Dir['spec/support/external_shared/*.rb']
31
31
 
32
- spec.add_dependency "rails", [">= 7.0", "< 8.1"]
32
+ spec.add_dependency "rails", [">= 7.0", "< 9.0"]
33
33
  # Policy
34
34
  spec.add_dependency "pundit", ["~> 2.3", ">= 2.3.1"]
35
35
  # Search
@@ -1 +1 @@
1
- 1.10.0
1
+ 1.12.0
@@ -7,18 +7,20 @@ module BaseEditingBootstrap::Searches
7
7
  include ActiveModel::Naming
8
8
  include ActiveModel::Conversion
9
9
 
10
- attr_reader :model_klass, :user, :params, :scope, :sorts, :distinct
10
+ attr_reader :model_klass, :user, :params, :scope, :sorts, :distinct, :display_action_column
11
11
 
12
12
  # @param [User] user
13
13
  # @param [ActiveRecord::Associations::CollectionProxy] scope
14
14
  # @param [Array<String (frozen)>] sort
15
- def initialize(scope, user, params: {page: nil}, sorts: ["id"], distinct: true)
15
+ # @param [TrueClass,FalseClass] display_action_column => visualizzare o meno la colonna delle azioni
16
+ def initialize(scope, user, params: {page: nil}, sorts: ["id"], distinct: true, display_action_column: true)
16
17
  @model_klass = scope.klass
17
18
  @user = user
18
19
  @scope = scope
19
20
  @params = params
20
21
  @sorts = sorts
21
22
  @distinct = distinct
23
+ @display_action_column = display_action_column
22
24
  end
23
25
 
24
26
  ##
@@ -8,6 +8,7 @@ RSpec.describe <%= class_name %>, type: :model do
8
8
  # ransack_permitted_associations: [],
9
9
  # option_label_method: :to_s,
10
10
  # ransack_permitted_scopes: [] do
11
+ # let(:option_label_instance){described_class.new} <- default, for override instance to check option_label_method
11
12
  # let(:auth_object) { :auth_object } <- default
12
13
  # let(:auth_object) { create(:user, :as_admin) } <- in caso di necessità di override
13
14
  # let(:new_user_ransack_permitted_attributes) { ransack_permitted_attributes }
@@ -3,6 +3,8 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [],
3
3
  option_label_method: :to_s,
4
4
  ransack_permitted_scopes: []|
5
5
 
6
+
7
+ let(:option_label_instance){described_class.new}
6
8
  it_behaves_like "a validated? object"
7
9
 
8
10
  it "human_action_message" do
@@ -10,11 +12,10 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [],
10
12
  end
11
13
 
12
14
  it "have method for belongs_to options" do
13
- instance = described_class.new
14
- expect(instance).to respond_to(:option_label)
15
+ expect(option_label_instance).to respond_to(:option_label)
15
16
 
16
- expect(instance).to receive(option_label_method).and_call_original, "Expected `#{instance.class}#option_label` chiami il metodo `##{option_label_method}` per la traduzione del label nelle options"
17
- instance.option_label
17
+ expect(option_label_instance).to receive(option_label_method).and_call_original, "Expected `#{option_label_instance.class}#option_label` chiami il metodo `##{option_label_method}` per la traduzione del label nelle options"
18
+ option_label_instance.option_label
18
19
  end
19
20
 
20
21
  if ransack_permitted_scopes.any?
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.10.0
4
+ version: 1.12.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-09-12 00:00:00.000000000 Z
11
+ date: 2025-12-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -19,7 +19,7 @@ dependencies:
19
19
  version: '7.0'
20
20
  - - "<"
21
21
  - !ruby/object:Gem::Version
22
- version: '8.1'
22
+ version: '9.0'
23
23
  type: :runtime
24
24
  prerelease: false
25
25
  version_requirements: !ruby/object:Gem::Requirement
@@ -29,7 +29,7 @@ dependencies:
29
29
  version: '7.0'
30
30
  - - "<"
31
31
  - !ruby/object:Gem::Version
32
- version: '8.1'
32
+ version: '9.0'
33
33
  - !ruby/object:Gem::Dependency
34
34
  name: pundit
35
35
  requirement: !ruby/object:Gem::Requirement
@@ -346,6 +346,7 @@ files:
346
346
  - app/views/base_editing/_form_fields_container.html.erb
347
347
  - app/views/base_editing/_form_footer.html.erb
348
348
  - app/views/base_editing/_form_footer_container.html.erb
349
+ - app/views/base_editing/_form_full_components.html.erb
349
350
  - app/views/base_editing/_index_body.html.erb
350
351
  - app/views/base_editing/_index_main_buttons.html.erb
351
352
  - app/views/base_editing/_index_title_header.html.erb
@@ -364,7 +365,8 @@ files:
364
365
  - app/views/base_editing/cell_field/_enum.html.erb
365
366
  - app/views/base_editing/cell_field/_timestamps.html.erb
366
367
  - app/views/base_editing/edit.html.erb
367
- - app/views/base_editing/form_field/_accept_nested_field.html.erb
368
+ - app/views/base_editing/form_field/_accept_has_many_nested_field.html.erb
369
+ - app/views/base_editing/form_field/_accept_has_one_nested_field.html.erb
368
370
  - app/views/base_editing/form_field/_base.html.erb
369
371
  - app/views/base_editing/form_field/_belongs_to_select.html.erb
370
372
  - app/views/base_editing/form_field/_boolean.html.erb