hot-glue 0.6.29 → 0.6.30
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 +53 -7
- data/lib/generators/hot_glue/fields/association_field.rb +1 -1
- data/lib/generators/hot_glue/layout_strategy/bootstrap.rb +0 -1
- data/lib/generators/hot_glue/scaffold_generator.rb +34 -8
- data/lib/generators/hot_glue/templates/controller.rb.erb +8 -7
- 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: 7eb77747230d52128ce322520c8c208c5e235cb27cca4042c99a0ce0e910382b
|
4
|
+
data.tar.gz: 9ba630157d1335f28acb15c7342f2d3489e63358ad38fd4d19185162fceb6895
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 990d8138a2916b7599ea831b8c2d09d70b5df653a0ec8b2f88632eae696c21ecd24406ec1d0b8ea180ffdc2fe1401a2030672d6e7c5695693e2c86d1222a01e5
|
7
|
+
data.tar.gz: c396428e8d84b06fe05483add1a9d89ea7149e303efef49d14cccafe3ce25312440b8620db4a5d79fe0bd9e4876b71e98bbac895a540a24cdd7f1b752afb2711
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -558,22 +558,24 @@ The child object is named `Rule` but it can belong to a Blast or an Agent. (Agen
|
|
558
558
|
|
559
559
|
We build the blast & agent controllers like so:
|
560
560
|
|
561
|
-
|
562
|
-
bin/rails generate hot_glue:scaffold
|
561
|
+
|
562
|
+
`bin/rails generate hot_glue:scaffold Blast --downnest='blast_rules(rules)'`
|
563
|
+
|
564
|
+
`bin/rails generate hot_glue:scaffold Agent --downnest='agent_rules(rules)'`
|
563
565
|
|
564
566
|
Notice that the relationship name is `rules` (not blast_rules), so what goes before the parenthesis is the controller name (with prefix)
|
565
567
|
What goes inside the controller name is the real relationship name.
|
566
568
|
|
567
569
|
For the children, we can't build one controller for the Rule, instead we build one for the `AgentRules` and another for the `BlastRules`
|
568
570
|
|
569
|
-
bin/rails generate hot_glue:scaffold Rule --nested='blast(ruleable)' --controller-prefix='Blast'
|
570
|
-
bin/rails generate hot_glue:scaffold Rule --nested='agent(ruleable)' --controller-prefix='Agent'
|
571
|
+
`bin/rails generate hot_glue:scaffold Rule --nested='blast(ruleable)' --controller-prefix='Blast'`
|
572
|
+
`bin/rails generate hot_glue:scaffold Rule --nested='agent(ruleable)' --controller-prefix='Agent'`
|
571
573
|
|
572
574
|
(I realize building one child controller for each type of polymorph is tedius, but this is the best solution I could come up with.)
|
573
575
|
|
574
576
|
As these are children, what goes into the `--netsed` setting inside the parentheses is the polymorphic name specified by `as:` when declaring the `belongs_to`
|
575
577
|
|
576
|
-
routes.rb
|
578
|
+
config/routes.rb
|
577
579
|
|
578
580
|
```
|
579
581
|
resources :agents do
|
@@ -585,6 +587,22 @@ routes.rb
|
|
585
587
|
end
|
586
588
|
```
|
587
589
|
|
590
|
+
Outside a polymorphic relationship, you sometimes have children with `belongs_to` that uses a custom name instead of the name of the class (using class_name on the belongs to)
|
591
|
+
|
592
|
+
Imagine a `followings` table with two foreign keys: follower_id and follows_id (both pointing to a BskyUser)
|
593
|
+
|
594
|
+
|
595
|
+
`belongs_to :follower, class_name: "BskyUser", foreign_key: :follower_id`
|
596
|
+
`belongs_to :follows, class_name: "BskyUser", foreign_key: :follows_id`
|
597
|
+
|
598
|
+
|
599
|
+
Here, specify nested using square braces for the non-standard parent name
|
600
|
+
|
601
|
+
`--nested='bsky_users[follower]'` and `--nested='bsky_users[follows]'`
|
602
|
+
|
603
|
+
|
604
|
+
|
605
|
+
|
588
606
|
### `--stacked-downnesting`
|
589
607
|
|
590
608
|
This puts the downnested portals on top of one another (stacked top to bottom) instead of side-by-side (left to right). This is useful if you have a lot of downnested portals and you want to keep the page from getting too wide.
|
@@ -2161,8 +2179,30 @@ This means that to find users within the search, the essential piece of informat
|
|
2161
2179
|
end
|
2162
2180
|
```
|
2163
2181
|
|
2182
|
+
If you want your typeahead to accept an input for a non-matched field, you need to use a factory (see `--factory-creation`)
|
2183
|
+
|
2184
|
+
Here, we assume that Authors are nested within a library (an arbitrary abstraction to demonstrate a typeahead at a nested route)
|
2185
|
+
|
2186
|
+
```
|
2187
|
+
factory = AuthorsFactory.new(
|
2188
|
+
library: library,
|
2189
|
+
query: params[:authors_query],
|
2190
|
+
author_params: modified_params)
|
2191
|
+
```
|
2192
|
+
|
2193
|
+
Your authors factory will need to check the params for `author_params[:author_id].empty?`
|
2164
2194
|
|
2165
2195
|
|
2196
|
+
When the factory is passed an empty string here, it is from a non-matched lookup. You will either lookup the author_id if provided, or create a new one if not
|
2197
|
+
```
|
2198
|
+
if !author_params[:author_id].empty?
|
2199
|
+
author = Author.find(author_params[:author_id])
|
2200
|
+
else
|
2201
|
+
author = Target.find_or_create_by!(library: library, name: query)
|
2202
|
+
end
|
2203
|
+
```
|
2204
|
+
Notice this is creating a new author by the `name` field, which should be same field you are searching by in the typeahead.
|
2205
|
+
|
2166
2206
|
--
|
2167
2207
|
|
2168
2208
|
|
@@ -2244,13 +2284,19 @@ These automatic pickups for partials are detected at build time. This means that
|
|
2244
2284
|
|
2245
2285
|
# VERSION HISTORY
|
2246
2286
|
|
2247
|
-
#### 2025-10-
|
2287
|
+
#### 2025-10-19 - v0.6.30
|
2288
|
+
- fixes references from search typeaheads to a typeahead controller which is nested
|
2289
|
+
- `--nested` can now take square braces if the relationship from child to parent (belongs_to) uses a non-standard association name; @downnest_object fix for data array; changes to object_scope to accomodate new paradigm
|
2290
|
+
|
2291
|
+
|
2292
|
+
|
2293
|
+
#### 2025-10-11 - v0.6.29
|
2248
2294
|
|
2249
2295
|
• When specifying a alt lookup in non-Gd mode, we treat this a security concern because alt lookups can get any related record from the database; if you use a factory when creating your object, you can pass the lookup to the factory and scope your lookup in there; fix to not raise exception when specified an alt lookup in non-Gd mode if you are also using a factory
|
2250
2296
|
|
2251
2297
|
• Attachments now have a graceful fail if the attachment is invariable (cannot be made into a thumbnail), and so there is no thumbnail to display. Instead, a small box with the file type ("pdf" or "msword") is shown in place where the thumbnail would display
|
2252
2298
|
|
2253
|
-
• Adds a '
|
2299
|
+
• Adds a 'triple' implementation for newer pagination gems: will_paginate and pagy. HG will auto detect which pagination gem you have in your Gemfile, and pick ONE of the three based on this preference order: Pagy over will_paginate; will_paginate over Kaminari, no pagination if none of the three are installed.
|
2254
2300
|
|
2255
2301
|
Kaminari is barely workable with newer Rails and seems somewhat abandoned; will_paginate is officially in maintenance mode, so Pagy is the way to go. I have implemented all three for the widest legacy support. On my Rails Cookbook pages, I have replaced Kaminari with Pagy.
|
2256
2302
|
|
@@ -204,7 +204,7 @@ class AssociationField < Field
|
|
204
204
|
assoc_name = name.to_s.gsub("_id","")
|
205
205
|
assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
|
206
206
|
if modify_as && modify_as[:typeahead]
|
207
|
-
search_url = "#{namespace ? namespace + "_" : ""}#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
|
207
|
+
search_url = "#{namespace ? namespace + "_" : ""}#{modify_as[:nested] ? modify_as[:nested][0] + "_" : ""}#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
|
208
208
|
|
209
209
|
# \"q[0][#{name}_search]\"
|
210
210
|
# @q['0']['#{name}_search']
|
@@ -456,11 +456,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
456
456
|
|
457
457
|
child_name.gsub!("+","")
|
458
458
|
|
459
|
-
|
460
|
-
@downnest_object[child] = {
|
459
|
+
@downnest_object[child_name] = {
|
461
460
|
name: child_name,
|
462
461
|
extra_size: extra_size,
|
463
|
-
polymorph_as: polymorph_as
|
462
|
+
polymorph_as: polymorph_as,
|
464
463
|
}
|
465
464
|
end
|
466
465
|
end
|
@@ -512,17 +511,27 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
512
511
|
|
513
512
|
if !@nested.nil?
|
514
513
|
@nested_set = @nested.split("/").collect { |arg|
|
515
|
-
if arg.include?("(")
|
514
|
+
if arg.include?("[") && arg.include?("(")
|
515
|
+
arg =~ /(.*)\((.*)\)\[(.*)\]/
|
516
|
+
singular, polymorph_as, parent_name = $1, $2, $3
|
517
|
+
|
518
|
+
elsif arg.include?("(")
|
516
519
|
arg =~ /(.*)\((.*)\)/
|
517
520
|
singular, polymorph_as = $1, $2
|
521
|
+
parent_name = singular
|
522
|
+
elsif arg.include?("[")
|
523
|
+
arg =~ /(.*)\[(.*)\]/
|
524
|
+
singular, parent_name = $1, $2
|
518
525
|
else
|
519
526
|
singular = arg
|
527
|
+
parent_name = singular
|
520
528
|
end
|
521
529
|
|
522
530
|
{
|
523
531
|
singular: singular,
|
524
532
|
plural: singular.pluralize,
|
525
|
-
polymorph_as: polymorph_as
|
533
|
+
polymorph_as: polymorph_as,
|
534
|
+
parent_name: parent_name
|
526
535
|
}
|
527
536
|
}
|
528
537
|
puts "NESTING: #{@nested_set}"
|
@@ -1426,17 +1435,34 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1426
1435
|
end
|
1427
1436
|
|
1428
1437
|
def object_scope
|
1438
|
+
if @nested_set.any? && @nested_set.last[:parent_name]
|
1439
|
+
last_parent = @nested_set.last[:parent_name]
|
1440
|
+
foreign_key = eval("#{singular_class}.reflect_on_association(:#{last_parent})").foreign_key
|
1441
|
+
association = eval(singular_class).reflect_on_association(@nested_set.last[:parent_name].to_sym)
|
1442
|
+
.klass.reflect_on_all_associations(:has_many)
|
1443
|
+
.to_a.find{|x|
|
1444
|
+
|
1445
|
+
if x.source_reflection
|
1446
|
+
x.foreign_key == foreign_key
|
1447
|
+
|
1448
|
+
# raise "#{singular_class} class declaration is missing source reflection for the `has_many :#{x.name}` association"
|
1449
|
+
end
|
1450
|
+
}.plural_name
|
1451
|
+
else
|
1452
|
+
association = plural
|
1453
|
+
end
|
1454
|
+
|
1429
1455
|
if @auth && !@god
|
1430
1456
|
if @nested_set.none?
|
1431
|
-
@auth + ".#{
|
1457
|
+
@auth + ".#{association}"
|
1432
1458
|
else
|
1433
|
-
"@" + @nested_set.last[:singular] + ".#{
|
1459
|
+
"@" + @nested_set.last[:singular] + ".#{association}"
|
1434
1460
|
end
|
1435
1461
|
else
|
1436
1462
|
if @nested_set.none?
|
1437
1463
|
@singular_class
|
1438
1464
|
else
|
1439
|
-
"@" + @nested_set.last[:singular] + ".#{
|
1465
|
+
"@" + @nested_set.last[:singular] + ".#{association}"
|
1440
1466
|
end
|
1441
1467
|
end
|
1442
1468
|
end
|
@@ -24,15 +24,15 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
24
24
|
before_action :<%= arg[:singular] %><%= ", if: -> { params.include?(:#{arg[:singular]}_id) }" if arg[:optional] %><% } %><% end %>
|
25
25
|
before_action :load_<%= singular_name %>, only: %i[<%= "show edit update" unless @no_edit %> <%= "destroy" unless @no_delete %>]
|
26
26
|
after_action -> { flash.discard }, if: -> { request.format.symbol == :turbo_stream }<% if @nested_set.any? %>
|
27
|
-
|
27
|
+
|
28
|
+
def <%= @nested_set[0][:singular] %><% if @god
|
28
29
|
next_object = nil
|
29
30
|
collect_objects = @nested_set.reverse.collect {|x|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
# if eval("#{next_object || class_name}.reflect_on_association(:#{x[:singular]})")
|
34
|
-
next_object = eval("#{next_object || class_name}.reflect_on_association(:#{x[:singular]})").class_name
|
31
|
+
assoc_name = x[:parent_name] || x[:singular]
|
32
|
+
# if eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").nil?
|
33
|
+
# 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
34
|
# end
|
35
|
+
next_object = eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").class_name
|
36
36
|
}
|
37
37
|
root_object = collect_objects.last
|
38
38
|
else
|
@@ -42,6 +42,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
42
42
|
root_object = @auth + "." + @nested_set[0][:plural]
|
43
43
|
end
|
44
44
|
end
|
45
|
+
|
45
46
|
%><% if !@god && @nested_set[0][:singular] == @auth_identifier %>
|
46
47
|
@<%= @nested_set[0][:singular] %> ||= <%= root_object %>
|
47
48
|
<% else %>
|
@@ -63,7 +64,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
63
64
|
def load_<%= singular_name %>
|
64
65
|
<% if @nested_set[0] && @nested_set[0][:optional] %>if params.include?(:<%= @nested_set.last[:singular] %>_id)
|
65
66
|
@<%= singular_name %> = <%= object_scope.gsub("@",'') %>.find(params[:id])
|
66
|
-
else <% end %>@<%= singular_name %> = <%= object_scope %>.find(params[:id])<% if @nested_set[0] && @nested_set[0][:optional] %>
|
67
|
+
else <% end %>@<%= singular_name %> = <%= object_scope.gsub("@",'') %>.find(params[:id])<% if @nested_set[0] && @nested_set[0][:optional] %>
|
67
68
|
end<% end %>
|
68
69
|
end
|
69
70
|
<% else %>
|
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.6.
|
4
|
+
version: 0.6.30
|
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-10-
|
11
|
+
date: 2025-10-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|