hot-glue 0.5.19.2 → 0.5.21

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: 016741b47374d4b624bb04c96757bf92ca48bef198ca39ff642d94b571024949
4
- data.tar.gz: 91ac3ecd1745958f7df484cb1ad009b63e02891e8f9021e7c7cd062aff7baaf6
3
+ metadata.gz: 34d4899a5495270c4364848ad5e61527141d1f2b869e3e55c24efb6c63865ac9
4
+ data.tar.gz: 1a97496b55af910b3c14ead50c92205e0e8ed7c6d75330050041a8e9c6aa4df7
5
5
  SHA512:
6
- metadata.gz: 32b258df9e7f7d989d7827aa5ed420019bc6283447822f254a01ebfc4dd705dcb2428d73f9685a65ed2e6157b114a38a8395144f351a16144f03b61ecc4c26c7
7
- data.tar.gz: e66eea5d26d987815a0583c80e49401a55fefaa59e5a2db503cc7fe488c403103a5699895966e73415dd2ca0de21452022cd1b68445859e8338330376c7aacf0
6
+ metadata.gz: 9aea82f09683d50f8e4175777fff16ef07da0682055cbe3ee29f3da3360a2b8763cfc079afe15c69f3e05f3b4dd33d063b63aa483c5e32ad60c2ac20da305f65
7
+ data.tar.gz: e3ec284bdb6d2d7d1030502fc45858c55afaf82e97fda92fd0bcb7359a7f54315a360aacd9bfd7e23da56dff08541ed0f120f2bc071faab950990688b40fb2ea
data/Gemfile CHANGED
@@ -24,7 +24,7 @@ gem "sprockets-rails"
24
24
  gem "importmap-rails"
25
25
  gem "stimulus-rails"
26
26
  gem "turbo-rails"
27
- gem "byebug"
27
+
28
28
 
29
29
  gem "puma", "~> 5.0"
30
30
 
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.5.19.1)
4
+ hot-glue (0.5.20)
5
5
  ffaker (~> 2.16)
6
6
  kaminari (~> 1.2)
7
7
  rails (> 5.1)
data/README.md CHANGED
@@ -75,15 +75,11 @@ For Hot Glue, you will need:
75
75
 
76
76
  Section #1 is to create a new Rails app. (Or you can do that yourself.)
77
77
 
78
- Section #2 is to setup Rspec, FactoryBot, and Faker.
78
+ Section #2 is to setup Rspec, FactoryBot, and Faker — choose 2B for Rspec0
79
79
 
80
- Section #4 is optional but highly recommended.
80
+ Skip #3 and #4 is optional. #5 is optional but recommended.
81
81
 
82
- Section #5 is where you will pick a CSS Framework (Bootstrap, Tailwind, or none)
83
-
84
- Section #6 is for two support gems (Kaminari) for Hot Glue
85
-
86
- Section #7 is for Hot Glue itself
82
+ Sectoin #6 is for Hot Glue itself, and Section #7 is for Kaminari
87
83
 
88
84
  You will also need section #8 to setup Devise if you want authentication.
89
85
 
@@ -645,15 +641,6 @@ This is what would happen if 9 fields, specified in the order A,B,C,D,E,F,G,H,I,
645
641
 
646
642
 
647
643
 
648
- ### `--show-only=`
649
- (separate field names by COMMA)
650
-
651
- Any fields only the 'show-only' list will appear as non-editable on the generated form for both new & edit actions. (visible only)
652
-
653
- IMPORTANT: By default, all fields that begin with an underscore (`_`) are automatically show-only.
654
-
655
- This is for fields you want globally non-editable by users in your app. For example, a counter cache or other field set only by a backend mechanism.
656
-
657
644
  ### `--modify=field1{...},field2{...}`
658
645
 
659
646
 
@@ -685,12 +672,92 @@ The available modifiers are:
685
672
  | truthy label\|falsy label | specify a binary switch with a pipe (\|) character if the value is truthy, it will display as "truthy label" if the value is falsy, it will display as "falsy label" | boolean, datetime, date, time | | |
686
673
  | | | | | |
687
674
 
675
+ ### `--pundit`
676
+ If you enable Pundit, your controllers will look for a Policy that matches the name of the thing being built.
677
+
678
+ **Realtime Field-level Access**
679
+ Hot Glue gives you automatic field level access control if you create `*_able?` methods for each field you'd like to control on your Pundit policy.
680
+
681
+ (Although this is not what Pundit recommends for field level access control, it has been implemented this way to provide field-by-field user feedback to the user shown in red just like Rails validation errors are currently shown. This is is only hypothetical, because the interface correctly shows the field as viewable or editable anyway, making bad entry only something that could be achieved through a mistake or hacking. Nevertheless, rest assured that if there was a input mistake-- like a user having a field editable when it shouldn't be, the backend policy would guard against the disallowed input and show an error message.)
682
+
683
+ The `*_able?` method should return true or false depending on whether or not the field can be edited. (No distinction is made between the different contexts. You may check if the record is new using `new_record?`.
684
+
685
+ The `*_able?` method is used by Hot Glue only on the new and edit actions, but you should incorporate it into the policy's `update?` method as in the example, which will extend other operations since Hot Glue will use the policy to authorize the action
686
+ Add one `*_able?` method to the policy for each field you want to allow field-level access control.
687
+
688
+ Replace `*` with the name of the field you want under access control. Remember to include `_id` for foreign keys. You do not need it for any field you don't want under access control.
689
+
690
+ When the method returns true, the field will be displayed to the user (and allowed) for editing.
691
+ When the method returns false, the field will be displayed as read-only (viewable) to the user.
692
+
693
+ Important: These special fields determine *only* display behavior (new and edit), not create and update.
694
+
695
+ For create & update field-level access control, you must also implement the `update?` method on the Policy. Notice how in the example policy below, the `update?` method uses the `name_able?` method when it is checking if the name field can be updated, tying the feature together.
696
+
697
+ You can set Pundit to be enabled globally on the whole project for every build in `config/hot_glue.yml` (then you can leave off the `--pundit` flag from the scaffold command)
698
+ `:pundit_default:` (all builds in that project will use Pundit)
699
+
700
+
701
+ Here's an example `ThingPolicy` that would allow **editing the name field** only if:
702
+ • the current user is an admin
703
+ • the sent_at date is nil (meaning it has not been sent yet)
704
+
705
+ For your policies, copy the `initialize` method of both the outer class (`ThingPolicy`) and the inner class (`Scope`) exactly as shown below.
706
+
707
+
708
+ ```
709
+ class ThingPolicy < ApplicationPolicy
710
+ def initialize(user, record)
711
+ @user = user
712
+ @record = record
713
+ end
714
+
715
+ def name_able?
716
+ @record.sent_at.nil?
717
+ end
718
+
719
+ def update?
720
+ if !@user.is_admin?
721
+ return false
722
+ elsif record.name_changed? && !name_able?
723
+ record.errors.add(:name, "cannot be changed.")
724
+ return false
725
+ else
726
+ return true
727
+ end
728
+ end
729
+
730
+ class Scope < Scope
731
+ attr_reader :user, :scope
732
+ def initialize(user, scope)
733
+ @user = user
734
+ @scope = scope
735
+ end
736
+ end
737
+ end
738
+ ```
739
+
740
+
741
+ Because Hot Glue detects the `*_able?` methods at build time, if you add them to your policy, you will have to rebuild your scaffold.
742
+
743
+
744
+ ### `--show-only=`
745
+ (separate field names by COMMA)
746
+
747
+ • Make this field appear as viewable only all actions. (visible only)
748
+ • When set on this list, it will override any Pundit policy even when Pundit would otherwise allow the access.
749
+
750
+ IMPORTANT: By default, all fields that begin with an underscore (`_`) are automatically show-only.
751
+
752
+ This is for fields you want globally non-editable by users in your app. For example, a counter cache or other field set only by a backend mechanism.
688
753
 
689
754
 
690
755
  ### `--update-show-only`
691
756
  (separate field names by COMMA)
692
757
 
693
- Fields on the `update show only` (and not on the `show only` list) will appear as non-editible only for the **edit** action, but will still allow entry for the **create** action.
758
+ Make this field appear as viewable only for the edit action (and not allowed in the update action).
759
+ • When set on this list, it will override any Pundit policy for edit/update actions even when Pundit would otherwise allow the access.
760
+
694
761
 
695
762
  Note that Hot Glue still generates a singular partial (`_form`) for both actions, but your form will now contain statements like:
696
763
 
@@ -705,6 +772,35 @@ Note that Hot Glue still generates a singular partial (`_form`) for both actions
705
772
  This works for both regular fields, association fields, and alt lookup fields.
706
773
 
707
774
 
775
+ When mixing the show only, update show only, and Pundit features, notice that the show only + update show only will act to override whatever the policy might say.
776
+
777
+ Remember, the show only list is specified using `--show-only` and the update show only list is specified using `--update-show-only`.
778
+
779
+ 'Viewable' means it displays as view-only (not editable) even on the form. In this context, 'viewable' means 'read-only'. It does not mean 'visible'.
780
+
781
+ That's because when the field is **not viewable**, then it is editable or inputable. This may seem counter-intuitive for a standard interpretation of the word 'viewable,' but consider that Hot Glue has been carefully designed this way. If you do not want the field to appear at all, then you simply remove it using the exclude list or don't specify it in your include list. If the field is being built at all, Hot Glue assumes your users want to see or edit it. Other special cases are beyond the scope of Hot Glue but can easily be added using direct customization of the code.
782
+
783
+ Without Pundit:
784
+ | | on new screen | on edit screen |
785
+ |------------------------------------------|---------------|----------------|
786
+ | for a field on the show only list | viewable | viewable |
787
+ | for a field on the update show only list | inputable | viewable |
788
+ | for all other fields | inputable | inputable |
789
+
790
+
791
+ With Pundit:
792
+ | | on new screen | on edit screen |
793
+ |------------------------------------------|---------------|----------------|
794
+ | for a field on the show only list | viewable | viewable |
795
+ | for a field on the update show only list | check policy | viewable |
796
+ | for all other fields | check policy | check policy |
797
+ | | | |
798
+
799
+ Remember, if there's a corresponding `*_able?` method on the policy, it will be used to determine if the field is **editable** or not in the cases where 'check policy' is above.
800
+ (where `*` is the name of your field)
801
+
802
+ As shown in the method `name_able?` of the example ThingPolicy above, if this field on your policy returns true, the field will be editable. If it returns false, the field will be viewable (read-only).
803
+
708
804
 
709
805
  ### `--ujs_syntax=true` (Default is set automatically based on whether you have turbo-rails installed)
710
806
 
@@ -813,6 +909,14 @@ Omits new & create actions.
813
909
 
814
910
  Omits delete button & destroy action.
815
911
 
912
+ ### `--no-controller`
913
+
914
+ Omits controller.
915
+
916
+ ### `--no-list`
917
+
918
+ Omits list views.
919
+
816
920
  ### `--big-edit`
817
921
 
818
922
  If you do not want inline editing of your list items but instead want to fall back to full page style behavior for your edit views, use `--big-edit`. Turbo still handles the page interactions, but the user is taken to a full-screen edit page instead of an edit-in-place interaction.
@@ -1300,6 +1404,20 @@ end
1300
1404
 
1301
1405
  # VERSION HISTORY
1302
1406
 
1407
+
1408
+ #### 2023-09-18 - v0.5.21
1409
+ - Removes `@` symbols using instance variables in `_edit` partials and in the enum syntax
1410
+ - fixes in system_spec.rb.erb
1411
+ - Adds flags --no-controller --no-list
1412
+ - adds regen code to a file in the views folder REGENERATE.md if you have set --no-controller
1413
+
1414
+
1415
+ #### 2023-09-08 - v0.5.20
1416
+ `--pundit` authorization
1417
+ • Will look for a `XyzPolicy` class and method on your class named `*_able?` matching the fields on your object. See Pundit section for details.
1418
+ • Field-level access control (can determine which fields are editble or viewable based on the record or current user or combination factors)
1419
+ • The field-level access control doesn't show the fields as editable to the user if they can't be edited by the user (it shows them as view-only).
1420
+
1303
1421
  #### 2023-09-02 - v0.5.19
1304
1422
 
1305
1423
  Given a table generated with this schema:
@@ -104,7 +104,7 @@ class AssociationField < Field
104
104
  end
105
105
 
106
106
  (is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
107
- " <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{name} }, class: 'form-control') %>\n" +
107
+ " <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, {prompt: true, selected: #{singular}.#{name} }, class: 'form-control') %>\n" +
108
108
  (is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
109
109
  (is_owner ? "\n<% end %>" : "")
110
110
  end
@@ -116,7 +116,7 @@ class AssociationField < Field
116
116
 
117
117
  def form_show_only_output
118
118
  assoc_name = name.to_s.gsub("_id","")
119
- assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
119
+ assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
120
120
  if assoc.nil?
121
121
  exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
122
122
  exit
@@ -37,7 +37,7 @@ class DateTimeField < Field
37
37
  "<%= datetime_field_localized(f, :#{name}, #{singular}.#{name}, '#{ name.to_s.humanize }') %>"
38
38
  end
39
39
 
40
- def line_field_output
40
+ def viewable_output
41
41
  if modify_binary?
42
42
  modified_display_output
43
43
  else
@@ -115,7 +115,7 @@ class Field
115
115
  end
116
116
 
117
117
  def modified_display_output
118
- if modify[:cast] && modify[:cast] == "$"
118
+ if modify[:cast] && modify[:cast] == "$"
119
119
  "<%= number_to_currency(#{singular}.#{name}) %>"
120
120
  elsif modify[:binary]
121
121
  "<%= #{singular}.#{name} ? '#{modify[:binary][:truthy]}' : '#{modify[:binary][:falsy]}' %>"
@@ -8,7 +8,7 @@ module HotGlue
8
8
  :inline_list_labels, :layout_object,
9
9
  :columns, :col_identifier, :singular,
10
10
  :form_placeholder_labels, :hawk_keys, :update_show_only,
11
- :alt_lookups, :attachments, :show_only, :columns_map
11
+ :alt_lookups, :attachments, :show_only, :columns_map, :pundit
12
12
 
13
13
 
14
14
  def initialize(singular:, singular_class: ,
@@ -17,7 +17,7 @@ module HotGlue
17
17
  ownership_field: , form_labels_position: ,
18
18
  inline_list_labels: ,
19
19
  form_placeholder_labels:, hawk_keys: ,
20
- update_show_only:, alt_lookups: , attachments: , columns_map: )
20
+ update_show_only:, alt_lookups: , attachments: , columns_map:, pundit: )
21
21
 
22
22
  @singular = singular
23
23
  @singular_class = singular_class
@@ -28,6 +28,7 @@ module HotGlue
28
28
  @small_buttons = small_buttons
29
29
  @layout_strategy = layout_strategy
30
30
  @show_only = show_only
31
+ @pundit = pundit
31
32
  @ownership_field = ownership_field
32
33
 
33
34
  @form_labels_position = form_labels_position
@@ -81,30 +82,34 @@ module HotGlue
81
82
  result = columns.map{ |column|
82
83
  " <div class='#{column_classes} cell--#{singular}--#{column.join("-")}' >" +
83
84
  column.map { |col|
84
- field_result = show_only.include?(col.to_sym) ?
85
- columns_map[col].form_show_only_output :
86
- columns_map[col].form_field_output
87
85
 
88
86
  field_error_name = columns_map[col].field_error_name
89
87
 
90
-
91
88
  label_class = columns_map[col].label_class
92
89
  label_for = columns_map[col].label_for
93
90
 
94
91
  the_label = "\n<label class='#{label_class}' for='#{label_for}'>#{col.to_s.humanize}</label>"
95
- show_only_open = ""
96
- show_only_close = ""
97
92
 
98
- if update_show_only.include?(col)
99
- show_only_open = "<% if action_name == 'edit' %>" +
100
- show_only_result(type: type, col: col, singular: singular) + "<% else %>"
101
- show_only_close = "<% end %>"
102
- end
93
+
94
+ field_result =
95
+ if show_only.include?(col)
96
+ columns_map[col].form_show_only_output
97
+ elsif update_show_only.include?(col) && !@pundit
98
+ "<% if action_name == 'edit' %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
99
+ elsif update_show_only.include?(col) && @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
100
+ "<% if action_name == 'create' && policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_show_only_output + "<% else %>" + columns_map[col].form_field_output + "<% end %>"
101
+
102
+ # show only on the update action overrides any pundit policy
103
+ elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
104
+ "<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
105
+ else
106
+ columns_map[col].form_field_output
107
+ end
103
108
 
104
109
  add_spaces_each_line( "\n <span class='<%= \"alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{'style="display: inherit;"'} >\n" +
105
110
  add_spaces_each_line( (form_labels_position == 'before' ? the_label : "") +
106
- show_only_open + field_result + show_only_close +
107
- (form_labels_position == 'after' ? the_label : "") , 4) +
111
+ + field_result +
112
+ (form_labels_position == 'after' ? the_label : "") , 4) +
108
113
  "\n </span>\n <br />", 2)
109
114
 
110
115
  }.join("") + "\n </div>"
@@ -21,7 +21,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
21
21
  :display_as, :downnest_children, :downnest_object, :hawk_keys, :layout_object, :modify,
22
22
  :nest_with, :path, :plural, :sample_file_path, :show_only_data, :singular,
23
23
  :singular_class, :smart_layout, :stacked_downnesting, :update_show_only, :ownership_field,
24
- :layout_strategy, :form_placeholder_labels, :form_labels_position
24
+ :layout_strategy, :form_placeholder_labels, :form_labels_position, :pundit
25
25
 
26
26
  class_option :singular, type: :string, default: nil
27
27
  class_option :plural, type: :string, default: nil
@@ -43,6 +43,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
43
43
  class_option :no_create, type: :boolean, default: false
44
44
  class_option :no_edit, type: :boolean, default: false
45
45
  class_option :no_list, type: :boolean, default: false
46
+ class_option :no_controller, type: :boolean, default: false
47
+ class_option :no_list, type: :boolean, default: false
46
48
  class_option :no_paginate, type: :boolean, default: false
47
49
  class_option :big_edit, type: :boolean, default: false
48
50
  class_option :show_only, type: :string, default: ""
@@ -81,6 +83,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
81
83
  class_option :button_icons, default: nil
82
84
  class_option :modify, default: {}
83
85
  class_option :display_as, default: {}
86
+ class_option :pundit, default: nil
84
87
 
85
88
  def initialize(*meta_args)
86
89
  super
@@ -288,6 +291,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
288
291
 
289
292
  @no_edit = options['no_edit'] || false
290
293
  @no_list = options['no_list'] || false
294
+ @no_controller = options['no_controller'] || false
295
+ @no_list = options['no_list'] || false
291
296
  @no_list_label = options['no_list_label'] || false
292
297
  @no_list_heading = options['no_list_heading'] || false
293
298
  @stacked_downnesting = options['stacked_downnesting']
@@ -295,6 +300,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
295
300
  @display_list_after_update = options['display_list_after_update'] || false
296
301
  @smart_layout = options['smart_layout']
297
302
 
303
+ @pundit = options['pundit']
304
+ if @pundit.nil?
305
+ @pundit = get_default_from_config(key: :pundit_default)
306
+ end
307
+
308
+
298
309
  if options['include'].include?(":") && @smart_layout
299
310
  raise HotGlue::Error, "You specified both --smart-layout and also specified grouping mode (there is a : character in your field include list); you must remove the colon(s) from your --include tag or remove the --smart-layout option"
300
311
  end
@@ -443,7 +454,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
443
454
  form_placeholder_labels: @form_placeholder_labels,
444
455
  alt_lookups: @alt_lookups,
445
456
  attachments: @attachments,
446
- columns_map: @columns_map
457
+ columns_map: @columns_map,
458
+ pundit: @pundit,
447
459
  )
448
460
  elsif @markup == "slim"
449
461
  raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
@@ -680,7 +692,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
680
692
 
681
693
  def copy_controller_and_spec_files
682
694
  @default_colspan = @columns.size
683
- unless @specs_only
695
+ unless @specs_only || @no_controller
684
696
  template "controller.rb.erb", File.join("#{filepath_prefix}app/controllers#{namespace_with_dash}", "#{@controller_build_folder}_controller.rb")
685
697
  if @namespace
686
698
  begin
@@ -806,7 +818,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
806
818
  show_only_list = which_partial == :create ? @show_only : (@update_show_only + @show_only)
807
819
 
808
820
  if show_only_list.include?(col)
809
- " page.should have_no_selector(:css, \"[name='#{testing_name}[#{ col.to_s }]'\")"
821
+ # TODO: decide if this should get re-implemeneted
822
+ # " page.should have_no_selector(:css, \"[name='#{testing_name}[#{ col.to_s }]'\")"
810
823
  else
811
824
  col_obj.spec_setup_and_change_act(which_partial)
812
825
  end
@@ -857,7 +870,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
857
870
  nested_set: @nested_set,
858
871
  with_params: true,
859
872
  put_form: true,
860
- top_level: true)
873
+ top_level: false)
861
874
  end
862
875
 
863
876
  def delete_path_helper
@@ -1012,6 +1025,11 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1012
1025
 
1013
1026
  def copy_view_files
1014
1027
  return if @specs_only
1028
+
1029
+ if @no_controller
1030
+ File.write("#{Rails.root}/app/views/#{namespace_with_trailing_dash}/#{plural}/REGENERATE.md", regenerate_me_code)
1031
+ end
1032
+
1015
1033
  all_views.each do |view|
1016
1034
  formats.each do |format|
1017
1035
  source_filename = cc_filename_with_extensions("#{@markup}/#{view}", "#{@markup}")
@@ -1111,6 +1129,11 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1111
1129
  if !(@no_edit && @no_create)
1112
1130
  res << '_form'
1113
1131
  end
1132
+
1133
+ if @no_list
1134
+ res -= %w{_list _line index}
1135
+ end
1136
+
1114
1137
  res
1115
1138
  end
1116
1139
 
@@ -65,21 +65,29 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
65
65
  @<%= singular_name %> = (<%= auth_object.gsub("@",'') %><%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set.any? && @nested_set[0][:optional] %>)<% if @nested_set.any? && @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %>
66
66
  end<% end %>
67
67
 
68
- def load_all_<%= plural %><% if !@self_auth %>
68
+ def load_all_<%= plural %><% if @pundit %>
69
+ @<%= plural_name %> = policy_scope(<%= class_name %>).page(params[:page])<%= n_plus_one_includes %>
70
+ authorize @<%= plural_name %>.all<% else %> <% if !@self_auth %>
69
71
  @<%= plural_name %> = <%= object_scope.gsub("@",'') %>.page(params[:page])<%= n_plus_one_includes %><%= " if params.include?(:#{ @nested_set.last[:singular]}_id)" if @nested_set.any? && @nested_set[0] && @nested_set[0][:optional] %><% if @nested_set[0] && @nested_set[0][:optional] %>
70
72
  @<%= plural_name %> = <%= class_name %>.all<% end %><% else %>
71
- @<%= plural_name %> = <%= class_name %>.where(id: <%= auth_object.gsub("@",'') %>.id)<%= n_plus_one_includes %> # returns iterable even though this <%= singular_name %> is only allowed access to themselves<% end %>
73
+ @<%= plural_name %> = <%= class_name %>.where(id: <%= auth_object.gsub("@",'') %>.id)<%= n_plus_one_includes %><% end %>
74
+ <% end %>
72
75
  end
73
76
 
74
77
  def index
75
- load_all_<%= plural %>
78
+ load_all_<%= plural %><% if @pundit %>
79
+ rescue Pundit::NotAuthorizedError
80
+ flash[:alert] = "You are not authorized to perform this action."<% end %>
76
81
  end
77
82
 
78
83
  <% if create_action %> def new<% if @object_owner_sym %>
79
- @<%= singular_name %> = <%= class_name %>.new(<% if eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)<% elsif @object_owner_optional && any_nested? %>
80
- @<%= singular_name %> = <%= class_name %>.new({}.merge(<%= @nested_set.last[:singular] %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}))<% else %>
81
- @<%= singular_name %> = <%= class_name %>.new(<% if any_nested? %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)
82
- <% end %>
84
+ @<%= singular_name %> = <% if @pundit %>policy_scope(<% end %><%= class_name %><% if @pundit %>)<% end %>.new(<% if eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)<% elsif @object_owner_optional && any_nested? %>
85
+ @<%= singular_name %> = <% if @pundit %>policy_scope(<% end %><%= class_name %><% if @pundit %>)<% end %>.new({}.merge(<%= @nested_set.last[:singular] %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}))<% else %>
86
+ @<%= singular_name %> = <% if @pundit %>policy_scope(<% end %><%= class_name %><% if @pundit %>)<% end %>.new(<% if any_nested? %><%= @object_owner_sym %>: <%= @object_owner_eval %><% end %>)<% end %>
87
+ <% if @pundit %>authorize @<%= singular_name %><% end %><% if @pundit %>
88
+ rescue Pundit::NotAuthorizedError
89
+ flash[:alert] = "You are not authorized to perform this action."
90
+ render :index<% end %>
83
91
  end
84
92
 
85
93
  def create
@@ -106,12 +114,18 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
106
114
  else
107
115
  flash[:alert] = "Oops, your <%= singular_name %> could not be created. #{@hawk_alarm}"
108
116
  render :create, status: :unprocessable_entity
109
- end
117
+ end<% if @pundit %>
118
+ rescue Pundit::NotAuthorizedError
119
+ flash[:alert] = "Creating <%= singular %> not authorized. #{@<%= singular %>.errors.collect{|k| "#{k.attribute} #{k.message}"}.join(" ")} #{flash[:notice]} "
120
+ render :index <% end %>
110
121
  end
111
122
 
112
123
  <% end %>
113
124
  <% unless @no_edit %> def edit
114
- render :edit
125
+ render :edit<% if @pundit %>
126
+ rescue Pundit::NotAuthorizedError
127
+ flash[:alert] = "Editing #{@<%= singular %>.<%= display_class %>} not authorized."
128
+ render :index <% end %>
115
129
  end
116
130
 
117
131
  <% end %><% if @build_update_action %> def update
@@ -120,7 +134,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
120
134
  }.join("\n") %><% end %> <% merge_lookups = @alt_lookups.filter{|key,d| ! @update_show_only.include?(key.to_sym) }.collect{|key, data| "#{key.gsub("_id", "")}: #{key.gsub("_id", "")}" }.join(",") %>
121
135
  <% @magic_buttons.each { |button| %>@<%= singular_name %>.<%= button %>! if <%= singular_name %>_params[:__<%= button %>]
122
136
  <% } %>
123
- modified_params = modify_date_inputs_on_params(<%= singular_name %>_params.dup<%= controller_update_params_tap_away_alt_lookups %>, <%= current_user_object %>, <%= datetime_fields_list %>) <% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
137
+ modified_params = modify_date_inputs_on_params(<% if @update_show_only %>update_<% end %><%= singular_name %>_params.dup<%= controller_update_params_tap_away_alt_lookups %>, <%= current_user_object %>, <%= datetime_fields_list %>) <% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
124
138
  modified_params = modified_params.merge(<%= @object_owner_sym %>: <%= @object_owner_eval %>) <% elsif @object_owner_optional && any_nested? %>
125
139
  modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% elsif !@object_owner_eval.empty? %>
126
140
  modified_params = modified_params.merge(<%= @object_owner_eval %>) <% end %><% if !merge_lookups.empty? %>
@@ -136,7 +150,13 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
136
150
  <%= @update_alt_lookups.collect{|key, data|
137
151
  " @#{ singular_name }.#{key.gsub("_id", "")} = #{key.gsub("_id", "")}"
138
152
  }.join("/n") %><% end %><%= controller_attachment_orig_filename_pickup_syntax %>
153
+ <% if @pundit %>
154
+ if @<%= singular_name %>.attributes = modified_params
155
+ authorize @<%= singular_name %>
156
+ @<%= singular_name %>.save
157
+ <% else %>
139
158
  if @<%= singular_name %>.update(modified_params)
159
+ <% end %>
140
160
  <% if @display_list_after_update %> load_all_<%= plural %><% end %>
141
161
  flash[:notice] = "#{flash[:notice]} Saved #{@<%= singular %>.<%= display_class %>}"
142
162
  flash[:alert] = @hawk_alarm if @hawk_alarm
@@ -144,22 +164,33 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
144
164
  else
145
165
  flash[:alert] = "#{flash[:notice]} <%= singular_name.titlecase %> could not be saved. #{@hawk_alarm}"
146
166
  render :update, status: :unprocessable_entity
147
- end
167
+ end<% if @pundit %>
168
+ rescue Pundit::NotAuthorizedError
169
+ flash[:alert] = "Updating #{@<%= singular_name %>.<%= display_class %>} not authorized. "
170
+ render :update<% end %>
148
171
  end
149
172
 
150
173
  <% end %><% if destroy_action %> def destroy
174
+ <% if @pundit %>authorize @<%= singular_name %><% end %>
151
175
  begin
152
176
  @<%=singular_name%>.destroy
153
177
  flash[:notice] = '<%= singular_name.titlecase %> successfully deleted'
154
178
  rescue StandardError => e
155
179
  flash[:alert] = '<%= singular_name.titlecase %> could not be deleted'
156
180
  end <%= post_action_parental_updates %>
157
- load_all_<%= plural %>
181
+ load_all_<%= plural %><% if @pundit %>
182
+ rescue Pundit::NotAuthorizedError
183
+ flash[:alert] = "Deleting #{@<%= singular_name %>.<%= display_class %>} not authorized. "
184
+ render :update<% end %>
158
185
  end<% end %>
159
186
 
160
187
  def <%=singular_name%>_params
161
- params.require(:<%= testing_name %>).permit(<%= (fields_filtered_for_email_lookups - @show_only) + @magic_buttons.collect{|x| "__#{x}".to_sym }%>)
162
- end
188
+ params.require(:<%= testing_name %>).permit(<%= (fields_filtered_for_email_lookups - @show_only ) + @magic_buttons.collect{|x| "__#{x}".to_sym }%>)
189
+ end<% if @update_show_only %>
190
+
191
+ def update_<%=singular_name%>_params
192
+ params.require(:<%= testing_name %>).permit(<%= (fields_filtered_for_email_lookups - @update_show_only) + @magic_buttons.collect{|x| "__#{x}".to_sym }%>)
193
+ end<% end %>
163
194
 
164
195
  def namespace
165
196
  <% if @namespace %>'<%= @namespace %>/'<% else %><% end %>
@@ -1,12 +1,11 @@
1
- <\%= turbo_frame_tag "<%= @namespace %>__#{dom_id(@<%= singular %>)}" do %>
1
+ <\%= turbo_frame_tag "<%= @namespace %>__#{dom_id(<%= singular %>)}" do %>
2
2
  <div class="cell editable" style="position: relative;">
3
- <\% if @<%= singular %>.errors.any? %>
4
- <\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: @<%= singular %> }) %>
3
+ <\% if <%= singular %>.errors.any? %>
4
+ <\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= singular %> }) %>
5
5
  <\% end %>
6
-
7
- <h2>Editing <\%= @<%= @singular %>.<%= display_class %> %></h2>
8
- <\%= form_with model: <%= "@" + singular %>, url: <%= form_path_edit_helper %> do |f| %>
9
- <\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {:<%= singular %> => <%= "@" + singular%>, f: f}<%= @nested_set.collect{|arg| ".merge(@#{arg[:singular]} ? {#{arg[:singular]}: @#{arg[:singular]}} : {})" }.join %> \%>
6
+ <h2>Editing <\%= <%= singular %>.<%= display_class %> %></h2>
7
+ <\%= form_with model: <%= singular %>, url: <%= form_path_edit_helper %> do |f| %>
8
+ <\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {:<%= singular %> => <%= singular %>, f: f}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> \%>
10
9
  <\% end %>
11
10
  </div>
12
11
  <\% end %>
@@ -15,7 +15,7 @@ describe 'interaction for <%= controller_class_name %>' do
15
15
  <% unless @god %>let(:<%= @auth %>) {create(:<%= @auth.gsub('current_', '') %>)}<% end %>
16
16
  <%= spec_related_column_lets %>
17
17
  let!(:<%= singular %>1) {create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> <%= item1_addOns %> )}
18
- <%= objest_nest_factory_setup %> <% unless @god || @existing_content.include?("login_as")%>
18
+ <%= objest_nest_factory_setup %> <% unless @god || (@existing_content && @existing_content.include?("login_as")) %>
19
19
  before do
20
20
  login_as(<%= @auth %>)
21
21
  end <% end %> <% if any_datetime_fields? %>
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.5.19.2'
3
+ CURRENT = '0.5.21'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot-glue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.19.2
4
+ version: 0.5.21
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Fleetwood-Boldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2023-09-04 00:00:00.000000000 Z
11
+ date: 2023-09-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails