hot-glue 0.7.1 → 0.7.2

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: 62c0a8b7999c39d4d93ece238d6447baa2ecdf34613d9fb11b5fe49842919424
4
- data.tar.gz: c0a2d741d113fe2d3a366b5f33f110fc5aa8956a1b52af7ea2deb56085e76a4b
3
+ metadata.gz: fede733fb9491fae14d59e1e00a446335a5bd613f600f4a12c141fd8cf497519
4
+ data.tar.gz: dab8840cd386193dfdf6b893edf02ccbeb5884f4b650c7abf6db8a06441b4e8d
5
5
  SHA512:
6
- metadata.gz: dd02b7553a585535eb7eb2ac195ce55eb0192151edccfb41cb9f3b4c8110ed125096200bbe3442cdc79dbb27db48cc0b8a10fdbc3366c9c0371f7ba46dc3684f
7
- data.tar.gz: 235257f2f9150c0ac038fd7b11d4ac0551d4a224213e5cf244311ed43ca4cbdc02e25bf6427090213e30abde0de7289a0b01b887e265f0e2496a63c9fc9b12e0
6
+ metadata.gz: 10547fd449b51c3b1968f10a3f1ae12c8a20190924d9b4dc39e338193e7c0095030b5455aa34701a7a0fb16bf85cfde39b9978248ce0aba024d9374f2c66bf96
7
+ data.tar.gz: 9b088a35487336500561ce7510cf6b3df90e8542cf05b6176c882630bfac91b783ad4f6ab94a519d195bc0506af624843a1aabf26117eb23ca7222efe1d2a634
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.7)
4
+ hot-glue (0.7.1)
5
5
  ffaker (~> 2.16)
6
6
  rails (> 5.1)
7
7
 
data/README.md CHANGED
@@ -712,6 +712,49 @@ current_user's has_many association (so, for any other "my" family, would be `cu
712
712
 
713
713
  This is covered in [Example #4 in the Hot Glue Tutorial](https://school.jfbcodes.com/8188)
714
714
 
715
+
716
+ ##### Using the object inside of the hawk
717
+ In the example above, we aren't using the name of the scaffold within the hawk.
718
+
719
+ However, if you are using the object's name in the hawk (for example `thing` for a `ThingsController`), the view will need this as a local variable `thing` and
720
+ the controller will need this as an instsance variable `@thing`
721
+
722
+ In this special case, Hot Glue converts the local variable `thing` used within your hawk code into instance variable `@thing`
723
+
724
+ For example, if we were building a Job scaffold, here we want restrict follow_up_target_id to a list
725
+ of eligible targets (in our case, with an email address that matches the company's website), we could use a view helper.
726
+
727
+ Notice that `targets_by_company` is defined in the helper below, and we pass it a relation from the current object which is `job`
728
+
729
+ `hot_glue:scaffold Job --hawk='follow_up_target_id{targets_by_company(job.company)}' --code-in-controller='include JobHelper;`
730
+ (notice that it is `job` not `@job`)
731
+
732
+ // app/helpers/job_helper.rb
733
+ ```
734
+ module JobHelper
735
+ def targets_by_company(company)
736
+ domain = company.website
737
+ Target.where("email LIKE ?", "%#{domain}%" )
738
+ end
739
+ end
740
+ ```
741
+
742
+ The generated controller code looks like:
743
+ ```
744
+ modified_params = hawk_params({follow_up_target_id: [targets_by_company(@job.company)]}, modified_params)
745
+ ```
746
+ (`hawk_param` is defined in Hot Glue itself. Notice that the `@` was appended to the front of `job`)
747
+
748
+ The edit form will look like this:
749
+ ```
750
+ <%= f.collection_select(:follow_up_target_id, targets_by_company(job.company), :id, :name, { prompt: true, selected: job.follow_up_target_id }) %>
751
+ ```
752
+ (In the _form view, the `job` is a local variable as we do not rely on the instance variables in subviews.)
753
+
754
+
755
+
756
+
757
+
715
758
  ### `--with-turbo-streams`
716
759
 
717
760
  If and only if you specify `--with-turbo-streams`, your views will contain `turbo_stream_from` directives. Whereas your views will always contain `turbo_frame_tags` (whether or not this flag is specified) and will use the Turbo stream replacement mechanism for non-idempotent actions (create & update). This flag just brings the magic of live-reload to the scaffold interfaces themselves.
@@ -2420,6 +2463,15 @@ These automatic pickups for partials are detected at build time. This means that
2420
2463
 
2421
2464
  # VERSION HISTORY
2422
2465
 
2466
+
2467
+ #### 2025-12-12
2468
+ - Using the object (of the scaffold being built) inside of the hawk now adds `@` to a variable named as the singular name of the scaffold;
2469
+ see "Using the object inside of the hawk"
2470
+ - error catching for missing parent relationships
2471
+ - fixes path for magic button when the controller has a prefix
2472
+ - fix nav active target for a controller with a prefix (the nav template uses the snake_case of the full controller name including prefix)
2473
+
2474
+
2423
2475
  #### 2025-11-12 - v0.7.1
2424
2476
  - in set searches, automatically sets the match field if the search text is input, removes match field (back to default) when search text is removed;
2425
2477
  -
@@ -2429,7 +2481,6 @@ These automatic pickups for partials are detected at build time. This means that
2429
2481
 
2430
2482
  - `--code-in-controller` option for inserting controller code directly into your controller
2431
2483
 
2432
-
2433
2484
  #### 2025-11-05 - v0.7
2434
2485
 
2435
2486
  Hot Glue already has a robust set of tools to provide field-by-field access control, hiding or turning visible-only fields by multiple methods, described under Access Control & Field Visibility Features.
@@ -754,51 +754,56 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
754
754
 
755
755
  if options['phantom_search']
756
756
  ps_input = options['phantom_search']
757
+ @phantom_search = {}
757
758
 
758
- ps_input =~ /(.*)\[(.*)\]/
759
- type_and_label, settings = $1, $2
760
759
 
760
+ ps_input.split(",").each do |input_setting|
761
+ input_setting =~ /(.*)\[(.*)\]/
762
+ type_and_label, settings = $1, $2
761
763
 
762
- type = type_and_label.split("_")[0]
763
- label = type_and_label.split("_")[1]
764
764
 
765
- @phantom_search = {}
766
- choices = settings.split("|")
765
+ type = type_and_label.split("_")[0]
766
+ label = type_and_label.split("_")[1]
767
767
 
768
+ choices = settings.split("|")
768
769
 
769
- @phantom_search[label.to_sym] = {
770
- type: type,
771
- name: label.humanize,
772
- choices: []
773
- }
774
770
 
775
- choices.each do |choice|
776
- if type == "radio"
777
- choice_label = choice.split(":")[0]
778
- choice_scope = choice.split(":")[1]
779
- elsif type == "checkboxes"
780
- choice_label = choice.split(":")[0]
781
- choice_scope_negative = choice.split(":")[1]
782
- choice_scope = choice.split(":")[2]
783
- end
771
+ @phantom_search[label.to_sym] = {
772
+ type: type,
773
+ name: label.humanize,
774
+ choices: []
775
+ }
784
776
 
785
- if choice_scope.nil? || choice_scope.strip.empty?
786
- choice_scope = "all"
787
- end
777
+ choices.each do |choice|
778
+ if type == "radio"
779
+ choice_label = choice.split(":")[0]
780
+ choice_scope = choice.split(":")[1]
781
+ elsif type == "checkboxes"
782
+ choice_label = choice.split(":")[0]
783
+ choice_scope_negative = choice.split(":")[1]
784
+ choice_scope = choice.split(":")[2]
785
+ end
788
786
 
789
- if choice_scope_negative.nil? || choice_scope_negative.strip.empty?
790
- choice_scope_negative = "all"
791
- end
787
+ if choice_scope.nil? || choice_scope.strip.empty?
788
+ choice_scope = "all"
789
+ end
790
+
791
+ if choice_scope_negative.nil? || choice_scope_negative.strip.empty?
792
+ choice_scope_negative = "all"
793
+ end
792
794
 
793
- choice_scope = ".#{choice_scope}" if !choice_scope.start_with?(".")
794
- choice_scope_negative = ".#{choice_scope_negative}" if !choice_scope_negative.start_with?(".")
795
+ choice_scope = ".#{choice_scope}" if !choice_scope.start_with?(".")
796
+ choice_scope_negative = ".#{choice_scope_negative}" if !choice_scope_negative.start_with?(".")
795
797
 
796
- @phantom_search[label.to_sym][:choices] << {
797
- label: choice_label,
798
- scope: choice_scope,
799
- scope_negative: choice_scope_negative,
800
- }
798
+ @phantom_search[label.to_sym][:choices] << {
799
+ label: choice_label,
800
+ scope: choice_scope,
801
+ scope_negative: choice_scope_negative,
802
+ }
803
+ end
801
804
  end
805
+
806
+
802
807
  puts "phantom search #{@phantom_search}"
803
808
  else
804
809
  @phantom_search = {}
@@ -906,6 +911,11 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
906
911
 
907
912
  end
908
913
 
914
+ def controller_prefix_snake
915
+ @controller_prefix&.underscore
916
+ end
917
+
918
+
909
919
  def setup_hawk_keys
910
920
  @hawk_keys = {}
911
921
 
@@ -1386,7 +1396,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1386
1396
  def form_path_edit_helper
1387
1397
  HotGlue.optionalized_ternary(namespace: @namespace,
1388
1398
  target: @singular,
1389
- prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
1399
+ prefix: (@controller_prefix ? controller_prefix_snake + "_" : ""),
1390
1400
  nested_set: @nested_set,
1391
1401
  with_params: false,
1392
1402
  put_form: true,
@@ -1394,17 +1404,18 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1394
1404
  end
1395
1405
 
1396
1406
  def delete_path_helper
1397
- HotGlue.optionalized_ternary(namespace: @namespace,
1398
- prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
1407
+ res = HotGlue.optionalized_ternary(namespace: @namespace,
1408
+ prefix: (@controller_prefix ? controller_prefix_snake + "_" : ""),
1399
1409
  target: @singular,
1400
1410
  nested_set: @nested_set,
1401
1411
  with_params: false,
1402
1412
  put_form: true)
1413
+ res
1403
1414
  end
1404
1415
 
1405
1416
  def edit_path_helper
1406
1417
  HotGlue.optionalized_ternary(namespace: @namespace,
1407
- prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
1418
+ prefix: (@controller_prefix ? controller_prefix_snake + "_" : ""),
1408
1419
  target: @singular,
1409
1420
  nested_set: @nested_set,
1410
1421
  modifier: "edit_",
@@ -1415,7 +1426,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1415
1426
  def new_path_name
1416
1427
  HotGlue.optionalized_ternary(namespace: @namespace,
1417
1428
  target: singular,
1418
- prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
1429
+ prefix: (@controller_prefix ? controller_prefix_snake + "_" : ""),
1419
1430
  nested_set: @nested_set,
1420
1431
  modifier: "new_",
1421
1432
  with_params: false)
@@ -1476,14 +1487,23 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1476
1487
  if @nested_set.any? && @nested_set.last[:parent_name]
1477
1488
  last_parent = @nested_set.last[:parent_name]
1478
1489
  foreign_key = eval("#{singular_class}.reflect_on_association(:#{last_parent})").foreign_key
1479
- association = eval(singular_class).reflect_on_association(@nested_set.last[:parent_name].to_sym)
1490
+ possible_associations = eval(singular_class).reflect_on_association(@nested_set.last[:parent_name].to_sym)
1480
1491
  .klass.reflect_on_all_associations(:has_many)
1481
- .to_a.find{|x|
1492
+ .to_a
1493
+
1482
1494
 
1495
+ association = possible_associations.find{|x|
1483
1496
  if x.source_reflection
1484
1497
  x.table_name == plural
1485
1498
  end
1486
- }.plural_name
1499
+ }
1500
+
1501
+ if !association
1502
+ klass = eval(singular_class).reflect_on_association(@nested_set.last[:parent_name].to_sym)
1503
+ .klass.to_s
1504
+ raise "Could not find relation #{plural} on #{klass}; maybe add `has_many :#{plural}` "
1505
+ end
1506
+ association = association.plural_name
1487
1507
 
1488
1508
  else
1489
1509
  association = plural
@@ -1552,16 +1572,19 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1552
1572
  end
1553
1573
 
1554
1574
  def magic_button_output
1575
+
1576
+
1555
1577
  @template_builder.magic_button_output(
1556
1578
  path: HotGlue.optionalized_ternary( namespace: @namespace,
1579
+ prefix: (@controller_prefix ? controller_prefix_snake + "_" : ""),
1557
1580
  target: @singular,
1558
1581
  nested_set: @nested_set,
1559
1582
  with_params: false,
1560
1583
  put_form: true),
1561
- big_edit: @big_edit,
1562
- singular: singular,
1563
- magic_buttons: @magic_buttons,
1564
- small_buttons: @small_buttons
1584
+ big_edit: @big_edit,
1585
+ singular: singular,
1586
+ magic_buttons: @magic_buttons,
1587
+ small_buttons: @small_buttons
1565
1588
  )
1566
1589
  end
1567
1590
 
@@ -1967,9 +1990,18 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1967
1990
  [name, file_format].compact.join(".")
1968
1991
  end
1969
1992
 
1970
- def hawk_to_ruby
1993
+ def hawk_to_ruby(in_controller: false) # false for views; true for controller
1994
+
1995
+
1971
1996
  res = @hawk_keys.collect { |k, v|
1972
- "#{k.to_s}: [#{v[:bind_to].join(".")}]"
1997
+ bind_to_array = v[:bind_to]
1998
+
1999
+ bind_to = bind_to_array.collect{|bt|
2000
+ bt.gsub!(singular, "@#{singular}") if in_controller
2001
+ bt
2002
+ }
2003
+
2004
+ "#{k.to_s}: [#{bind_to.join(".")}]"
1973
2005
  }.join(", ")
1974
2006
  res
1975
2007
  end
@@ -30,9 +30,12 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
30
30
  next_object = nil
31
31
  collect_objects = @nested_set.reverse.collect {|x|
32
32
  assoc_name = x[:parent_name] || x[:singular]
33
- # if eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").nil?
34
- # raise "***** Unable to find the association `#{assoc_name}` on the class #{next_object || class_name} ..... you probably want to add `belongs_to :#{assoc_name}` to the #{next_object || class_name} object?"
35
- # end
33
+ if eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").nil?
34
+ raise "***** Unable to find the association `#{assoc_name}` on the class #{next_object || class_name} ..... you probably want to add `belongs_to :#{assoc_name}` to the #{next_object || class_name} object?"
35
+ end
36
+
37
+
38
+
36
39
  next_object = eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").class_name
37
40
  }
38
41
  root_object = collect_objects.last
@@ -119,7 +122,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
119
122
 
120
123
  <%= controller_attachment_orig_filename_pickup_syntax %>
121
124
  <%= creation_syntax %>
122
- <%= @code_after_new ? @code_after_new.gsub(";","\n") + "\n" : "" %>
125
+ <%= @code_after_new ? @code_after_new.gsub(";","\n") + "\n" : "" %>
126
+ <% if @hawk_keys.any? %> modified_params = hawk_params({<%= hawk_to_ruby(in_controller: true) %>}, modified_params)<% end %>
123
127
 
124
128
  <% if @pundit %><% @related_sets.each do |key, related_set| %>
125
129
  check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :create)<% end %><% end %>
@@ -219,7 +223,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
219
223
  "#{field_name}: #{field_name}" unless @update_show_only.include?(lookup.to_sym)
220
224
  }.join(",") %>)
221
225
  <% end %>
222
- <% if @hawk_keys.any? %> modified_params = hawk_params({<%= hawk_to_ruby %>}, modified_params)<% end %>
226
+ <% if @hawk_keys.any? %> modified_params = hawk_params({<%= hawk_to_ruby(in_controller: true) %>}, modified_params)<% end %>
223
227
  <%= controller_attachment_orig_filename_pickup_syntax %>
224
228
  @<%= singular_name %>.assign_attributes(modified_params)
225
229
  <% if @pundit && !@pundit_policy_override %>
@@ -1,7 +1,7 @@
1
1
  <\%= turbo_frame_tag "<%= @namespace %>__#{dom_id(<%= singular %>)}" do %>
2
2
  <div class="cell editable" style="position: relative;">
3
3
  <\% if <%= singular %>.errors.any? %>
4
- <\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= singular %> }) %>
4
+ <\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= "#{singular}" %> }) %>
5
5
  <\% end %>
6
6
  <h2>Editing <%= singular + " " if @include_object_names %><\%= <%= singular %>.<%= display_class %> %></h2>
7
7
  <\%= form_with model: <%= singular %>,
@@ -1,5 +1,6 @@
1
1
  <% if @big_edit %>
2
- <% if include_nav_template %><%= @layout_strategy.page_begin %><\%= render partial: "<%= nav_template %>", locals: {nav: "<%= @plural %>"} %><%= @layout_strategy.page_end %><% end %>
2
+ <% if include_nav_template %><%= @layout_strategy.page_begin %>
3
+ <\%= render partial: "<%= nav_template %>", locals: {nav: "<%= "#{@controller_prefix ? controller_prefix_snake + "_": ""}#{@plural}" %>"} %><%= @layout_strategy.page_end %><% end %>
3
4
 
4
5
  <div class="container">
5
6
  <div class="row">
@@ -1,7 +1,8 @@
1
1
  <% if @menu_file_exists %><\%= render partial: "<%= namespace_with_trailing_dash %>menu", locals: {active: '<%= plural %>'} %><% end %>
2
2
 
3
3
  <div class="<%= @container_name %>">
4
- <% if include_nav_template %><%= @layout_strategy.page_begin %><\%= render partial: "<%= nav_template %>", locals: {nav: "<%= @plural %>"} %><%= @layout_strategy.page_end %><% end %>
4
+ <% if include_nav_template %><%= @layout_strategy.page_begin %>
5
+ <\%= render partial: "<%= nav_template %>", locals: {nav: "<%= "#{@controller_prefix ? controller_prefix_snake + "_": ""}#{@plural}" %>"} %><%= @layout_strategy.page_end %><% end %>
5
6
  <% if @index_before_list_partial %><\%= render partial: "index_before_list" %><% end %>
6
7
 
7
8
  <%= @layout_strategy.page_begin %>
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.7.1'
3
+ CURRENT = '0.7.2'
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.7.1
4
+ version: 0.7.2
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: 2025-11-12 00:00:00.000000000 Z
11
+ date: 2025-12-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails