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 +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +52 -1
- data/lib/generators/hot_glue/scaffold_generator.rb +79 -47
- data/lib/generators/hot_glue/templates/controller.rb.erb +9 -5
- data/lib/generators/hot_glue/templates/erb/_edit.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/edit.erb +2 -1
- data/lib/generators/hot_glue/templates/erb/index.erb +2 -1
- data/lib/hotglue/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: fede733fb9491fae14d59e1e00a446335a5bd613f600f4a12c141fd8cf497519
|
|
4
|
+
data.tar.gz: dab8840cd386193dfdf6b893edf02ccbeb5884f4b650c7abf6db8a06441b4e8d
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 10547fd449b51c3b1968f10a3f1ae12c8a20190924d9b4dc39e338193e7c0095030b5455aa34701a7a0fb16bf85cfde39b9978248ce0aba024d9374f2c66bf96
|
|
7
|
+
data.tar.gz: 9b088a35487336500561ce7510cf6b3df90e8542cf05b6176c882630bfac91b783ad4f6ab94a519d195bc0506af624843a1aabf26117eb23ca7222efe1d2a634
|
data/Gemfile.lock
CHANGED
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
|
-
|
|
766
|
-
|
|
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
|
-
|
|
776
|
-
|
|
777
|
-
|
|
778
|
-
|
|
779
|
-
|
|
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
|
-
|
|
786
|
-
|
|
787
|
-
|
|
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
|
-
|
|
790
|
-
|
|
791
|
-
|
|
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
|
-
|
|
794
|
-
|
|
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
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
|
|
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 ?
|
|
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 ?
|
|
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 ?
|
|
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 ?
|
|
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
|
-
|
|
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
|
|
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
|
-
}
|
|
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
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
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
|
-
|
|
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
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
-
<%=
|
|
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
|
|
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
|
|
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 %>
|
data/lib/hotglue/version.rb
CHANGED
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.
|
|
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
|
+
date: 2025-12-12 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|