base_editing_bootstrap 1.6.0 → 1.7.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: 0f292b335541e77a9d78ae97f8ef87cc436468094aaccd69750dae0f8dcf44af
4
- data.tar.gz: 7c3f97b3261d736258efc021f36cc131943763b13f7d933cfb0967cbf58e5f36
3
+ metadata.gz: 9c363b9569d715a8519f72345250ee7dd019de73ce87330e6a49d62acc0e0e10
4
+ data.tar.gz: 9d7499c1ba5fbf66c2d0f466237e7b69bce234d022d21cd9d74b920564b6960f
5
5
  SHA512:
6
- metadata.gz: 3ec5909dab19b68590b2e2beb5dbcf7b502f2bbeb9ae3c2c244117837c4eeb54d20848ca30381f0cae4c88f6047bf3d55c2dfeef37dd28623b7b59933970e33c
7
- data.tar.gz: dbaca2890a7a8a6ea1f9cde44fcd6d07495a6f289ba82f62698cc8b9cac6bfe20809133590ca05c91cecd1078ea7ce4a87087c0501e52570146eca17efd65486
6
+ metadata.gz: b2243dc34ddba312f01465774a8df4662ea78e832885774966d29c685164201284aae102b8188a59c54d8b3c44a1c8af81227e04ef28a780651e6cdcd1abe6c1
7
+ data.tar.gz: 7c43ad6f7059a50c7719633e432d941ebd2433518712b9b5d20b5fff573cc802b24de785e81a96eebaf31c6d96639b2e3a99445dca3df086956d73a0529cc6d3
data/CHANGELOG.md CHANGED
@@ -2,6 +2,22 @@
2
2
  All notable changes to this project will be documented in this file. See [conventional commits](https://www.conventionalcommits.org/) for commit guidelines.
3
3
 
4
4
  - - -
5
+ ## 1.7.0 - 2025-02-11
6
+ #### Bug Fixes
7
+ - Add permits of ransack scopes - (5fa26c6) - Marino Bonetti
8
+ - Correct set select classes - (a5ef685) - Marino Bonetti
9
+ - Boolean_icon with nil value - (211c91f) - Marino Bonetti
10
+ - Better expection for spec helper - (65b26ce) - Marino Bonetti
11
+ #### Documentation
12
+ - Add documentation for help html version - (dbc1c01) - Marino Bonetti
13
+ #### Features
14
+ - Add HTML helper version in form field help - (f06c438) - Marino Bonetti
15
+ - Add Configurable distinct query in controller - (184d772) - Marino Bonetti
16
+ #### Tests
17
+ - Correct validation for selects - (e4b8016) - Marino Bonetti
18
+
19
+ - - -
20
+
5
21
  ## 1.6.0 - 2025-01-23
6
22
  #### Features
7
23
  - Add new test helper for association relation - (15690c7) - Marino Bonetti
data/README.md CHANGED
@@ -126,7 +126,8 @@ Utilizzo per modello base, in questo esempio prendiamo come modello Post come es
126
126
  ```
127
127
  - è possibile customizzare
128
128
  - un text help per ogni campo andando ad aggiungere nelle traduzioni la relativa
129
- traduzione nella posizione: `it.activerecord.attributes.MODEL.FIELD/help_text`
129
+ traduzione nella posizione: `it.activerecord.attributes.MODEL.FIELD/help_text` oppure `help_text_html` in caso di
130
+ contenuto con html
130
131
  - un blocco per l'unità di misura accanto al campo aggiungendo alle traduzioni:
131
132
  `it.activerecord.attributes.MODEL.FIELD/unit`
132
133
 
@@ -14,13 +14,19 @@ class BaseEditingController < RestrictedAreaController
14
14
  # Works like documented in https://activerecord-hackery.github.io/ransack/getting-started/sorting/#sorting-in-the-controller
15
15
  class_attribute :default_sorts, default: ["id"]
16
16
 
17
+ ##
18
+ # Configure default distinct results in the index query.
19
+ # Works like documented in https://activerecord-hackery.github.io/ransack/going-further/other-notes/#problem-with-distinct-selects
20
+ class_attribute :default_distinct, default: true
21
+
17
22
  def index
18
23
  authorize base_class
19
24
 
20
25
  q = policy_scope(base_scope)
21
26
  @search_instance = search_class.new(q, current_user,
22
27
  params: params.permit(:page, :q => {}), # FIXME trovare modo per essere più "STRONG"
23
- sorts: default_sorts
28
+ sorts: default_sorts,
29
+ distinct: default_distinct
24
30
  )
25
31
  @search_instance = yield(@search_instance) if block_given?
26
32
  end
@@ -1,4 +1,5 @@
1
1
  module Utilities::PageHelper
2
+ include Utilities::IconHelper
2
3
  # @param [BaseModel] base_class
3
4
  def title_mod_g(base_class)
4
5
  "#{t("edit")} #{base_class.model_name.human}"
@@ -24,12 +25,15 @@ module Utilities::PageHelper
24
25
  # end
25
26
  # end
26
27
 
27
- # @param [TrueClass, FalseClass] valore
28
+ # @param [TrueClass, FalseClass, NilClass] valore
28
29
  def boolean_to_icon(valore)
29
- if valore
30
+ case valore
31
+ when true
30
32
  icon("check-lg", class: "text-success")
31
- else
33
+ when false
32
34
  icon("x-lg", class: "text-danger")
35
+ else
36
+ nil
33
37
  end
34
38
  end
35
39
 
@@ -24,6 +24,8 @@ class BaseModelPolicy < ApplicationPolicy
24
24
  []
25
25
  end
26
26
 
27
+ def permitted_scopes_for_ransack = []
28
+
27
29
  def search_fields = []
28
30
 
29
31
  def search_result_fields = []
@@ -6,7 +6,13 @@
6
6
  %>
7
7
  <%# locals: (object:,field:) -%>
8
8
  <%
9
- help_text = object.class.human_attribute_name("#{field}/help_text", default: "")
9
+ nf = "NOT_FOUND_HTML"
10
+ help_text = object.class.human_attribute_name("#{field}/help_text_html", default: nf)
11
+ if help_text != nf
12
+ help_text = help_text.html_safe
13
+ else
14
+ help_text = object.class.human_attribute_name("#{field}/help_text", default: "")
15
+ end
10
16
  unless help_text.blank?
11
17
  %>
12
18
  <div class="form-text"><%= help_text %></div>
@@ -1 +1 @@
1
- 1.6.0
1
+ 1.7.0
@@ -7,7 +7,9 @@ module BaseEditingBootstrap
7
7
  included do
8
8
  include IsValidated
9
9
  include ActionTranslation
10
- delegate :ransackable_attributes, :ransackable_associations, to: :@class
10
+ delegate :ransackable_attributes,
11
+ :ransackable_associations,
12
+ :ransackable_scopes, to: :@class
11
13
 
12
14
 
13
15
  ##
@@ -34,6 +36,14 @@ module BaseEditingBootstrap
34
36
  Pundit.policy(User.new, self.new).permitted_associations_for_ransack.map(&:to_s)
35
37
  end
36
38
  end
39
+
40
+ def ransackable_scopes(auth_object = nil)
41
+ if auth_object
42
+ Pundit.policy(auth_object, self.new).permitted_scopes_for_ransack.map(&:to_s)
43
+ else
44
+ Pundit.policy(User.new, self.new).permitted_scopes_for_ransack.map(&:to_s)
45
+ end
46
+ end
37
47
  end
38
48
  end
39
49
  end
@@ -24,8 +24,8 @@ module BaseEditingBootstrap::Forms
24
24
  ##
25
25
  # Costruisce l'array delle classi che devono essere presenti sul campo della form
26
26
  #
27
- def form_style_class_for(method, options = {})
28
- classes = ["form-control"]
27
+ def form_style_class_for(method, options = {}, base_classes: ["form-control"])
28
+ classes = base_classes
29
29
  classes << "is-invalid" if object.errors && object.errors.include?(method)
30
30
  classes << options[:class].split(" ") if options[:class]
31
31
  classes.flatten.compact.uniq.join(" ")
@@ -46,8 +46,8 @@ module BaseEditingBootstrap::Forms
46
46
  end
47
47
 
48
48
  def select(method, choices = nil, options = {}, html_options = {}, &block)
49
- html_options[:class] = "form-select #{html_options[:class]}"
50
- super(method, choices, options, html_options.merge(class: form_style_class_for(method, html_options)), &block)
49
+ html_options.merge!(class: form_style_class_for(method, html_options, base_classes: ["form-control", "form-select"]))
50
+ super(method, choices, options,html_options , &block)
51
51
  end
52
52
 
53
53
  def check_box(method, options = {}, checked_value = "1", unchecked_value = "0")
@@ -57,9 +57,10 @@ module BaseEditingBootstrap::Forms
57
57
  else
58
58
  label_tag = nil
59
59
  end
60
- classes = (["form-check"] + (options.extract!(:class)[:class] || "").split(" ")).join(" ")
61
- @template.content_tag(:div, class: classes) do
62
- super(method, options.reverse_merge(class: "form-check-input"), checked_value, unchecked_value) + label_tag
60
+ @template.content_tag(:div, class: form_style_class_for(method, {class: (options.extract!(:class)[:class] || "")}, base_classes: ["form-check"])) do
61
+ checkbox_class = ["form-check-input"]
62
+ checkbox_class << "is-invalid" if object.errors && object.errors.include?(method)
63
+ super(method, options.reverse_merge(class: checkbox_class.join(" ")), checked_value, unchecked_value) + label_tag
63
64
  end
64
65
  end
65
66
 
@@ -75,7 +76,7 @@ module BaseEditingBootstrap::Forms
75
76
  options = {},
76
77
  html_options = {},
77
78
  &block)
78
- form_check_classes = (["form-check"] + [(html_options.delete(:form_check_class){""}).split(" ").collect(&:strip)]).compact.join(" ")
79
+ form_check_classes = (["form-check"] + [(html_options.delete(:form_check_class) { "" }).split(" ").collect(&:strip)]).compact.join(" ")
79
80
  super do |builder|
80
81
  @template.content_tag(:div, class: form_check_classes) do
81
82
  builder.check_box(class: "form-check-input") + builder.label(class: "form-check-label")
@@ -7,17 +7,18 @@ module BaseEditingBootstrap::Searches
7
7
  include ActiveModel::Naming
8
8
  include ActiveModel::Conversion
9
9
 
10
- attr_reader :model_klass, :user, :params, :scope, :sorts
10
+ attr_reader :model_klass, :user, :params, :scope, :sorts, :distinct
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"])
15
+ def initialize(scope, user, params: {page: nil}, sorts: ["id"], distinct: true)
16
16
  @model_klass = scope.klass
17
17
  @user = user
18
18
  @scope = scope
19
19
  @params = params
20
20
  @sorts = sorts
21
+ @distinct = distinct
21
22
  end
22
23
 
23
24
  ##
@@ -26,7 +27,7 @@ module BaseEditingBootstrap::Searches
26
27
  def results
27
28
  ransack_query
28
29
  .tap { |r| r.sorts = @sorts if r.sorts.empty? }
29
- .result(distinct: true)
30
+ .result(distinct: @distinct)
30
31
  .tap { |q| Rails.logger.debug { "[Ransack] params:#{params} - sql: #{q.to_sql}" } }
31
32
  .page(params[:page])
32
33
  end
@@ -5,11 +5,14 @@ RSpec.describe <%= class_name %>, type: :model do
5
5
 
6
6
  # it_behaves_like "a base model",
7
7
  # ransack_permitted_attributes: %w[<%= attributes_names.join(" ") %>],
8
- # ransack_permitted_associations: [] do
8
+ # ransack_permitted_associations: [],
9
+ # option_label_method: :to_s,
10
+ # ransack_permitted_scopes: [] do
9
11
  # let(:auth_object) { :auth_object } <- default
10
12
  # let(:auth_object) { create(:user, :as_admin) } <- in caso di necessità di override
11
13
  # let(:new_user_ransack_permitted_attributes) { ransack_permitted_attributes }
12
14
  # let(:new_user_ransack_permitted_associations) { ransack_permitted_associations }
15
+ # let(:new_user_ransack_permitted_scopes) { ransack_permitted_scopes }
13
16
  # end
14
17
 
15
18
  end
@@ -49,7 +49,9 @@ RSpec.shared_examples "base editing controller" do |factory: nil, only: [], exce
49
49
 
50
50
  ##
51
51
  # Possibili override per la costruzione delle path
52
- #
52
+
53
+ let(:default_sorts) { BaseEditingController.default_sorts } # configurazione nel controller per ordine di default del modello
54
+ let(:default_distinct) { BaseEditingController.default_distinct } # configurazione nel controller per distinct nella ricerca di ransack
53
55
  let(:url_for_new) { url_for([model.new, action: :new]) }
54
56
  let(:url_for_index) { url_for(model) }
55
57
  let(:url_for_create) { url_for(model.new) }
@@ -89,10 +91,13 @@ RSpec.shared_examples "base editing controller" do |factory: nil, only: [], exce
89
91
  params = {q: {"foo_eq": "foo"}}
90
92
  get url_for_index, params: params
91
93
  expect(response).to have_http_status(200)
92
- expect(assigns[:search_instance]).to be_an_instance_of(BaseEditingBootstrap::Searches::Base).and(have_attributes(
93
- user: user,
94
- params: ActionController::Parameters.new(params).permit!
95
- ))
94
+ expect(assigns[:search_instance]).to be_an_instance_of(BaseEditingBootstrap::Searches::Base)
95
+ .and(have_attributes(
96
+ user: user,
97
+ params: ActionController::Parameters.new(params).permit!,
98
+ sorts: default_sorts,
99
+ distinct: default_distinct,
100
+ ))
96
101
  end
97
102
  end
98
103
  end
@@ -194,7 +199,7 @@ default_unathorized_failure = -> { raise "TODO - passare proc con richiesta che
194
199
  RSpec.shared_examples "fail with unauthorized" do |request: default_unathorized_failure|
195
200
  it "is expected to redirect to root" do
196
201
 
197
- if Gem::Version.create( Pundit::VERSION) < Gem::Version.create('2.3.2')
202
+ if Gem::Version.create(Pundit::VERSION) < Gem::Version.create('2.3.2')
198
203
  allow(Pundit).to receive(:authorize).with(user, any_args).and_raise(Pundit::NotAuthorizedError)
199
204
  else
200
205
  allow_any_instance_of(Pundit::Context).to receive(:authorize).and_raise(Pundit::NotAuthorizedError)
@@ -1,4 +1,7 @@
1
- RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [], ransack_permitted_associations: [], option_label_method: :to_s|
1
+ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [],
2
+ ransack_permitted_associations: [],
3
+ option_label_method: :to_s,
4
+ ransack_permitted_scopes: []|
2
5
 
3
6
  it_behaves_like "a validated? object"
4
7
 
@@ -10,15 +13,24 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [], ransa
10
13
  instance = described_class.new
11
14
  expect(instance).to respond_to(:option_label)
12
15
 
13
- expect(instance).to receive(option_label_method).and_call_original
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"
14
17
  instance.option_label
15
18
  end
16
19
 
20
+ if ransack_permitted_scopes.any?
21
+ it "have scopes" do
22
+ ransack_permitted_scopes.each do |scope|
23
+ expect(described_class).to respond_to(scope)
24
+ end
25
+ end
26
+ end
27
+
17
28
  ##
18
29
  # Oggetto solitamente di classe User che identifichi l'utente a cui eseguire il check dei permessi
19
30
  let(:auth_object) { :auth_object }
20
31
  let(:new_user_ransack_permitted_attributes) { ransack_permitted_attributes }
21
32
  let(:new_user_ransack_permitted_associations) { ransack_permitted_associations }
33
+ let(:new_user_ransack_permitted_scopes) { ransack_permitted_scopes }
22
34
 
23
35
  describe "with ransackables" do
24
36
  where(:base_model_method, :result, :new_user_result) do
@@ -29,6 +41,9 @@ RSpec.shared_examples "a base model" do |ransack_permitted_attributes: [], ransa
29
41
  [
30
42
  :ransackable_associations, ransack_permitted_associations.map(&:to_s), lazy { new_user_ransack_permitted_associations.map(&:to_s) }
31
43
  ],
44
+ [
45
+ :ransackable_scopes, ransack_permitted_scopes.map(&:to_s), lazy { new_user_ransack_permitted_scopes.map(&:to_s) }
46
+ ],
32
47
  ]
33
48
  end
34
49
 
@@ -25,6 +25,7 @@ RSpec.shared_examples "a standard base model policy" do |factory, check_default_
25
25
  [:search_fields],
26
26
  [:permitted_associations_for_ransack],
27
27
  [:permitted_attributes_for_ransack],
28
+ [:permitted_scopes_for_ransack],
28
29
  [:editable_attributes],
29
30
  [:permitted_attributes],
30
31
  ]
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.6.0
4
+ version: 1.7.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-23 00:00:00.000000000 Z
11
+ date: 2025-02-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails