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 +4 -4
- data/CHANGELOG.md +26 -0
- data/README.md +22 -6
- data/app/controllers/base_editing_controller.rb +10 -5
- data/app/helpers/utilities/form_helper.rb +11 -3
- data/app/helpers/utilities/page_helper.rb +1 -2
- data/app/views/base_editing/_form.html.erb +1 -9
- data/app/views/base_editing/_form_full_components.html.erb +14 -0
- data/app/views/base_editing/_search_result.html.erb +2 -2
- data/app/views/base_editing/_search_result_row.html.erb +5 -3
- data/app/views/base_editing/form_field/_accept_has_one_nested_field.html.erb +4 -0
- data/base_editing_bootstrap.gemspec +1 -1
- data/lib/base_editing_bootstrap/VERSION +1 -1
- data/lib/base_editing_bootstrap/searches/base.rb +4 -2
- data/lib/generators/base_editing_bootstrap/scaffold/templates/spec/model.rb.tt +1 -0
- data/spec/support/external_shared/base_model.rb +5 -4
- metadata +7 -5
- /data/app/views/base_editing/form_field/{_accept_nested_field.html.erb → _accept_has_many_nested_field.html.erb} +0 -0
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 220d6cba364a9462e61d4db63e648b902899d92330afe32fa7f9844f898e5793
|
|
4
|
+
data.tar.gz: d74f68c4b7d6682b85dcde6089c41ec23a00596e848c6d7c98bcac89e14c5f67
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
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
|
-
#
|
|
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
|
-
-
|
|
214
|
-
|
|
215
|
-
|
|
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
|
|
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
|
-
|
|
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.
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
-
|
|
6
|
-
|
|
7
|
-
|
|
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>
|
|
@@ -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", "<
|
|
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.
|
|
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
|
-
|
|
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
|
-
|
|
14
|
-
expect(instance).to respond_to(:option_label)
|
|
15
|
+
expect(option_label_instance).to respond_to(:option_label)
|
|
15
16
|
|
|
16
|
-
expect(
|
|
17
|
-
|
|
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.
|
|
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-
|
|
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: '
|
|
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: '
|
|
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/
|
|
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
|
|
File without changes
|