hot-glue 0.7.5 → 0.7.7
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 +3 -3
- data/README.md +53 -1
- data/app/helpers/hot_glue/controller_helper.rb +27 -73
- data/lib/generators/hot_glue/field_factory.rb +1 -19
- data/lib/generators/hot_glue/fields/association_field.rb +7 -4
- data/lib/generators/hot_glue/fields/field.rb +3 -2
- data/lib/generators/hot_glue/markup_templates/erb.rb +18 -5
- data/lib/generators/hot_glue/scaffold_generator.rb +76 -35
- data/lib/generators/hot_glue/templates/controller.rb.erb +7 -10
- 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: 19812e0ed05939741ec5f22550345a5d94a07ad32f3925540bd6bb2ec76e0f6f
|
|
4
|
+
data.tar.gz: d2fba980427bd8c8961a6fb475b063305956d8a99ac428ffc28317291b961209
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 2a6c67fe502cce091097b4e72f1806a23b9126eea7c1498a8ba5f38aec5a581ddb59fd54543e4ba00257f70bfaa987aaf9ae07c9f80de093cccd0a3584dd9133
|
|
7
|
+
data.tar.gz: 3143a9b97b4338421c2bc4b910afd2f18cddb96178e8e27e6beaf4189d705d54222aa6335c425b7beb2ea2910557979135d84919c410ad63d3c357d3c5e06885
|
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.6.2)
|
|
5
5
|
ffaker (~> 2.16)
|
|
6
6
|
rails (> 5.1)
|
|
7
7
|
|
|
@@ -129,7 +129,7 @@ GEM
|
|
|
129
129
|
mini_mime (1.1.2)
|
|
130
130
|
mini_portile2 (2.8.4)
|
|
131
131
|
minitest (5.16.3)
|
|
132
|
-
net-imap (0.6.
|
|
132
|
+
net-imap (0.6.4)
|
|
133
133
|
date
|
|
134
134
|
net-protocol
|
|
135
135
|
net-pop (0.1.2)
|
|
@@ -225,7 +225,7 @@ GEM
|
|
|
225
225
|
stimulus-rails (1.1.1)
|
|
226
226
|
railties (>= 6.0.0)
|
|
227
227
|
thor (1.2.1)
|
|
228
|
-
timeout (0.6.
|
|
228
|
+
timeout (0.6.1)
|
|
229
229
|
turbo-rails (1.3.2)
|
|
230
230
|
actionpack (>= 6.0.0)
|
|
231
231
|
activejob (>= 6.0.0)
|
data/README.md
CHANGED
|
@@ -712,6 +712,17 @@ 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
|
+
##### Polymoprhism with the Hawk
|
|
716
|
+
|
|
717
|
+
If the field (foreign key) being hawked is a polymorphic foreign key, you need to list multiple objects which define the allowed scopes (one for each kind of parent type).
|
|
718
|
+
|
|
719
|
+
In this case, you will use **spaces** to separate scopes (NOT commas)
|
|
720
|
+
|
|
721
|
+
for example, if we have a `thing` that can belong (via parent_id and parent_type) to either people or places, we could restrict this thing to only people and places associated from the `account` object (which would be in-scope based on, for example, the nesting arrangement or a logged in-user, or the account currently being managed)
|
|
722
|
+
|
|
723
|
+
`--hawk=parent_id{account.people account.places}`
|
|
724
|
+
|
|
725
|
+
Hot glue wil convert the spaces to commas when writing the controller code.
|
|
715
726
|
|
|
716
727
|
##### Using the object inside of the hawk
|
|
717
728
|
In the example above, we aren't using the name of the scaffold within the hawk.
|
|
@@ -882,7 +893,7 @@ You may use semi-colons to separate multiple lines of code.
|
|
|
882
893
|
|
|
883
894
|
For example, a user Factory might be called like so:
|
|
884
895
|
|
|
885
|
-
`./bin/rails generate hot_glue:scaffold User --factory-creation=
|
|
896
|
+
`./bin/rails generate hot_glue:scaffold User --factory-creation='factory = UserFactory.new(params: user_params)' --gd`
|
|
886
897
|
|
|
887
898
|
(Note we are relying on the `user_params` method provided by the controller.)
|
|
888
899
|
|
|
@@ -2478,6 +2489,47 @@ These automatic pickups for partials are detected at build time. This means that
|
|
|
2478
2489
|
|
|
2479
2490
|
# VERSION HISTORY
|
|
2480
2491
|
|
|
2492
|
+
#### 2026-04-08 - v0.7.6.2
|
|
2493
|
+
- Syntax fix in code, no functional changes
|
|
2494
|
+
|
|
2495
|
+
#### 2026-04-06 - v0.7.6.1
|
|
2496
|
+
- Syntax fix in code, no functional changes
|
|
2497
|
+
|
|
2498
|
+
#### 2026-03-08 - v0.7.6
|
|
2499
|
+
- Makes hawk polymorphic aware. As well, a child controller with a polymorphic parent is also aware (the last item in the nest list should be specified using `(`...`)`)
|
|
2500
|
+
|
|
2501
|
+
Using the hawk with a polymorphic foreign key:
|
|
2502
|
+
|
|
2503
|
+
If the field (foreign key) being hawked is a polymorphic foreign key, you need to list multiple objects which define the allowed scopes (one for each kind of parent type).
|
|
2504
|
+
|
|
2505
|
+
In this case, you will use **spaces** to separate scopes (NOT commas)
|
|
2506
|
+
|
|
2507
|
+
for example, if we have a `thing` that can belong (via parent_id and parent_type) to either people or places, we could restrict this thing to only people and places associated from the `account` object (which would be in-scope based on, for example, the nesting arrangement or a logged in-user, or the account currently being managed)
|
|
2508
|
+
|
|
2509
|
+
`--hawk=parent_id{account.people account.places}`
|
|
2510
|
+
|
|
2511
|
+
Hot glue wil convert the spaces to commas when writing the controller code.
|
|
2512
|
+
|
|
2513
|
+
A child controller to with a polymorphic parent:
|
|
2514
|
+
- This special case assume that that the parent being build is not actually a polymoprh, it is a real object, but its children have foreign keys to it which are polymorphic.
|
|
2515
|
+
|
|
2516
|
+
`--nested=abc(parent) `
|
|
2517
|
+
|
|
2518
|
+
Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so tha this child controller will be built as CompanyTargets. In the companies build, we downnest `company_targets(targets)` (`company_targets` is the name of the child controller, but it is acting on an object called `targets`, as seen in the downnest specification.)
|
|
2519
|
+
|
|
2520
|
+
```
|
|
2521
|
+
bin/rails generate hot_glue:scaffold Company --namespace='account_dashboard' --nested='account' --downnest='company_targets(targets)'
|
|
2522
|
+
```
|
|
2523
|
+
|
|
2524
|
+
When building Targets, notice that the nested chain ends with `company(parent)`. This means our routes behave like normal routes (account/company), but this tells Hot Glue that the relationship from Target to Company is via the polymorphic parent_id & parent_type key.
|
|
2525
|
+
|
|
2526
|
+
```
|
|
2527
|
+
bin/rails generate hot_glue:scaffold Target --namespace='account_dashboard' --nested='account/company(parent)' --controller-prefix='Company'
|
|
2528
|
+
```
|
|
2529
|
+
|
|
2530
|
+
- Pagy support for Pagy 42 + 43. Breaking changes bewteen Pagy version 9 and version 42 force you to rebuild everything (every view) when upgrading Pagy. Hot Glue now detects which version of Pagy is installed and outputs the syntax for that version. (You will still need to rebuild all controllers when upgrading past Pagy 9)
|
|
2531
|
+
|
|
2532
|
+
|
|
2481
2533
|
#### 2026-01-11 - v0.7.5
|
|
2482
2534
|
This is mostly a maintenance release to address these two issues related to the hawk:
|
|
2483
2535
|
- removes the hawk in the create action because we are alrady doing it in the creation_syntax
|
|
@@ -120,68 +120,6 @@ module HotGlue
|
|
|
120
120
|
"#{sign}#{hour_abs}#{minute_str}"
|
|
121
121
|
end
|
|
122
122
|
|
|
123
|
-
# def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = {})
|
|
124
|
-
#
|
|
125
|
-
# use_timezone = if current_user_object.try(:timezone)
|
|
126
|
-
# (ActiveSupport::TimeZone[current_user_object.timezone])
|
|
127
|
-
# else
|
|
128
|
-
# Time.zone
|
|
129
|
-
# end
|
|
130
|
-
#
|
|
131
|
-
#
|
|
132
|
-
# uses_dst = (current_user_object.try(:locale_uses_dst)) || false
|
|
133
|
-
#
|
|
134
|
-
# modified_params = modified_params.tap do |params|
|
|
135
|
-
# params.keys.each{|k|
|
|
136
|
-
# if field_list.is_a?(Hash)
|
|
137
|
-
# include_me = field_list[k.to_sym].present?
|
|
138
|
-
# elsif field_list.is_a?(Array)
|
|
139
|
-
# field_list.include?(k.to_sym)
|
|
140
|
-
# end
|
|
141
|
-
#
|
|
142
|
-
# parsables = {
|
|
143
|
-
# datetime: "%Y-%m-%d %H:%M %z",
|
|
144
|
-
# time: "%H:%M %z"
|
|
145
|
-
# }
|
|
146
|
-
#
|
|
147
|
-
#
|
|
148
|
-
# if include_me && params[k].present?
|
|
149
|
-
# input_value = params[k].gsub("T", " ") # e.g. "2025-09-24 14:00" or "14:00"
|
|
150
|
-
#
|
|
151
|
-
# if field_list.is_a?(Array)
|
|
152
|
-
# # Datetime inputs (e.g. datetime-local)
|
|
153
|
-
# parsed_time = Time.strptime(input_value, "%Y-%m-%d %H:%M")
|
|
154
|
-
# parsed_time = parsed_time.utc.change(sec: 0)
|
|
155
|
-
# else
|
|
156
|
-
# case field_list[k.to_sym]
|
|
157
|
-
# when :datetime
|
|
158
|
-
# parsed_time = Time.strptime(input_value, "%Y-%m-%d %H:%M")
|
|
159
|
-
# parsed_time = parsed_time.utc.change(sec: 0)
|
|
160
|
-
# when :time
|
|
161
|
-
#
|
|
162
|
-
# Rails.logger.info("input_value: #{input_value}")
|
|
163
|
-
# # Parse as hour/minute only, no zone
|
|
164
|
-
# t = Time.strptime(input_value, "%H:%M")
|
|
165
|
-
#
|
|
166
|
-
# # Build a UTC time with today's date
|
|
167
|
-
# parsed_time = Time.utc(Time.now.year, Time.now.month, Time.now.day, t.hour, t.min, 0)
|
|
168
|
-
# # Convert back to a plain "time of day" (for DB `time` column)
|
|
169
|
-
# parsed_time = parsed_time.to_time.change(sec: 0)
|
|
170
|
-
# Rails.logger.info("parsed_time: #{parsed_time}")
|
|
171
|
-
#
|
|
172
|
-
# else
|
|
173
|
-
# raise "Unsupported field type: #{field_list[k.to_sym]}"
|
|
174
|
-
# end
|
|
175
|
-
# end
|
|
176
|
-
#
|
|
177
|
-
# Rails.logger.info "parsed_time #{parsed_time}"
|
|
178
|
-
# params[k] = parsed_time
|
|
179
|
-
# end
|
|
180
|
-
# }
|
|
181
|
-
# end
|
|
182
|
-
# modified_params
|
|
183
|
-
# end
|
|
184
|
-
|
|
185
123
|
def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = {})
|
|
186
124
|
use_timezone =
|
|
187
125
|
if current_user_object.try(:timezone)
|
|
@@ -229,17 +167,33 @@ module HotGlue
|
|
|
229
167
|
end
|
|
230
168
|
|
|
231
169
|
def hawk_params(hawk_schema, modified_params)
|
|
232
|
-
@hawk_alarm = ""
|
|
233
|
-
hawk_schema.each do |hawk_key,hawk_definition|
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
170
|
+
@hawk_alarm = +""
|
|
171
|
+
hawk_schema.each do |hawk_key, hawk_definition|
|
|
172
|
+
if hawk_definition[0].to_s.start_with?("[") # the hawk is polymorphic
|
|
173
|
+
# hawk_definition[0] is like "[account.companies,account.vc_firms]"
|
|
174
|
+
scopes = hawk_definition[0].to_s.gsub(/^\[|\]$/, "").split(",").map(&:strip)
|
|
175
|
+
|
|
176
|
+
unless modified_params[hawk_key.to_s].blank?
|
|
177
|
+
passed = scopes.any? do |scope_str|
|
|
178
|
+
relation = scope_str.split(".").inject(self) { |obj, method_name| obj.send(method_name) }
|
|
179
|
+
relation.where(id: modified_params[hawk_key.to_s]).exists?
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
unless passed
|
|
183
|
+
@hawk_alarm << "You aren't allowed to set #{hawk_key.to_s} to #{modified_params[hawk_key.to_s]}. "
|
|
184
|
+
modified_params.tap { |hs| hs.delete(hawk_key.to_s) }
|
|
185
|
+
end
|
|
186
|
+
end
|
|
187
|
+
else
|
|
188
|
+
hawk_root = hawk_definition[0]
|
|
189
|
+
unless modified_params[hawk_key.to_s].blank?
|
|
190
|
+
begin
|
|
191
|
+
|
|
192
|
+
hawk_definition.where(modified_params[hawk_key.to_s])
|
|
193
|
+
rescue ActiveRecord::RecordNotFound => e
|
|
194
|
+
@hawk_alarm << "You aren't allowed to set #{hawk_key.to_s} to #{modified_params[hawk_key.to_s]}. "
|
|
195
|
+
modified_params.tap { |hs| hs.delete(hawk_key.to_s) }
|
|
196
|
+
end
|
|
243
197
|
end
|
|
244
198
|
end
|
|
245
199
|
end
|
|
@@ -54,24 +54,6 @@ class FieldFactory
|
|
|
54
54
|
end
|
|
55
55
|
|
|
56
56
|
@field = field_class.new(scaffold: generator, name: name)
|
|
57
|
-
|
|
58
|
-
# form_placeholder_labels: generator.form_placeholder_labels,
|
|
59
|
-
# form_labels_position: generator.form_labels_position,
|
|
60
|
-
# ownership_field: generator.ownership_field,
|
|
61
|
-
# hawk_keys: generator.hawk_keys,
|
|
62
|
-
# auth: generator.auth,
|
|
63
|
-
# class_name: generator.singular_class,
|
|
64
|
-
# alt_lookup: generator.alt_lookups[name] || nil,
|
|
65
|
-
# singular: generator.singular,
|
|
66
|
-
# self_auth: generator.self_auth,
|
|
67
|
-
# update_show_only: generator.update_show_only,
|
|
68
|
-
# attachment_data: generator.attachments[name.to_sym],
|
|
69
|
-
# sample_file_path: generator.sample_file_path,
|
|
70
|
-
# modify_as: generator.modify_as[name.to_sym] || nil,
|
|
71
|
-
# plural: generator.plural,
|
|
72
|
-
# display_as: generator.display_as[name.to_sym] || nil,
|
|
73
|
-
# default_boolean_display: generator.default_boolean_display,
|
|
74
|
-
# namespace: generator.namespace_value,
|
|
75
|
-
# pundit: generator.pundit )
|
|
57
|
+
|
|
76
58
|
end
|
|
77
59
|
end
|
|
@@ -3,7 +3,7 @@ require_relative './field.rb'
|
|
|
3
3
|
|
|
4
4
|
class AssociationField < Field
|
|
5
5
|
|
|
6
|
-
attr_accessor :assoc_name, :assoc_class, :assoc, :alt_lookup
|
|
6
|
+
attr_accessor :assoc_name, :assoc_class, :assoc, :alt_lookup, :polymorphic_parents
|
|
7
7
|
|
|
8
8
|
def initialize(scaffold: , name: )
|
|
9
9
|
super
|
|
@@ -108,7 +108,7 @@ class AssociationField < Field
|
|
|
108
108
|
if @modify_as[:nested].any?
|
|
109
109
|
search_url << "(" + modify_as[:nested].collect{|x| "#{x}"}.join(",") + ")"
|
|
110
110
|
end
|
|
111
|
-
|
|
111
|
+
@polymorphic_parents = []
|
|
112
112
|
"<div class='typeahead typeahead--#{assoc.name}_id'
|
|
113
113
|
data-controller='typeahead'
|
|
114
114
|
data-typeahead-url-value='<%= #{search_url} %>'
|
|
@@ -118,8 +118,11 @@ class AssociationField < Field
|
|
|
118
118
|
autofocus: true,
|
|
119
119
|
autocomplete: 'off',
|
|
120
120
|
value: #{singular}.try(:#{assoc.name}).try(:name) %>
|
|
121
|
-
<%= f.hidden_field :#{assoc.name}_id, value: #{singular}.try(:#{assoc.name}).try(:id), 'data-typeahead-target': 'hiddenFormValue' %>
|
|
122
|
-
|
|
121
|
+
<%= f.hidden_field :#{assoc.name}_id, value: #{singular}.try(:#{assoc.name}).try(:id), 'data-typeahead-target': 'hiddenFormValue' %>" +
|
|
122
|
+
( @polymorphic_parents.include?( (assoc.name.to_s + "_id")) ?
|
|
123
|
+
"\n <%= f.hidden_field :#{assoc.name}_type, value: #{singular}.try(:#{assoc.name}_type), 'data-typeahead-target': 'hiddenFormType' %>"
|
|
124
|
+
: "") +
|
|
125
|
+
"\n <div data-typeahead-target='results'></div>
|
|
123
126
|
<div data-typeahead-target='classIdentifier' data-id=\"typeahead--#{assoc_name}_id\"></div>
|
|
124
127
|
</div>"
|
|
125
128
|
else
|
|
@@ -6,7 +6,8 @@ class Field
|
|
|
6
6
|
:self_auth,
|
|
7
7
|
:singular_class, :singular, :sql_type, :ownership_field,
|
|
8
8
|
:update_show_only, :namespace, :pundit, :plural,
|
|
9
|
-
:stimmify, :hidden_create, :hidden_update, :attachment_data, :god
|
|
9
|
+
:stimmify, :hidden_create, :hidden_update, :attachment_data, :god,
|
|
10
|
+
:polymorphic_parents
|
|
10
11
|
|
|
11
12
|
|
|
12
13
|
def initialize(
|
|
@@ -37,7 +38,7 @@ class Field
|
|
|
37
38
|
@hidden_update = scaffold.hidden_update
|
|
38
39
|
@attachment_data = scaffold.attachments[name.to_sym]
|
|
39
40
|
@god = scaffold.god
|
|
40
|
-
|
|
41
|
+
@polymorphic_parents = scaffold.polymorphic_parents
|
|
41
42
|
|
|
42
43
|
|
|
43
44
|
# TODO: remove knowledge of subclasses from Field
|
|
@@ -12,7 +12,8 @@ module HotGlue
|
|
|
12
12
|
:search, :search_fields, :search_query_fields, :search_position,
|
|
13
13
|
:form_path, :layout_object, :search_clear_button, :search_autosearch,
|
|
14
14
|
:stimmify, :stimmify_camel, :hidden_create, :hidden_update, :invisible_create,
|
|
15
|
-
:invisible_update, :plural, :phantom_search, :pagination_style
|
|
15
|
+
:invisible_update, :plural, :phantom_search, :pagination_style,
|
|
16
|
+
:namespace, :controller_build_folder
|
|
16
17
|
|
|
17
18
|
|
|
18
19
|
def initialize(singular:, singular_class: ,
|
|
@@ -26,7 +27,7 @@ module HotGlue
|
|
|
26
27
|
search_clear_button:, search_autosearch:, layout_object:,
|
|
27
28
|
form_path: , stimmify: , stimmify_camel:, hidden_create:, hidden_update: ,
|
|
28
29
|
invisible_create:, invisible_update: , plural: , phantom_search:,
|
|
29
|
-
pagination_style: )
|
|
30
|
+
pagination_style:, namespace: nil, controller_build_folder: nil )
|
|
30
31
|
|
|
31
32
|
|
|
32
33
|
@form_path = form_path
|
|
@@ -68,6 +69,12 @@ module HotGlue
|
|
|
68
69
|
@related_sets = related_sets
|
|
69
70
|
@phantom_search = phantom_search
|
|
70
71
|
@pagination_style = pagination_style
|
|
72
|
+
@namespace = namespace
|
|
73
|
+
@controller_build_folder = controller_build_folder
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
def pickup_partial_path(partial_name)
|
|
77
|
+
"#{@namespace + "/" if @namespace}#{@controller_build_folder}/#{partial_name}"
|
|
71
78
|
end
|
|
72
79
|
|
|
73
80
|
def add_spaces_each_line(text, num_spaces)
|
|
@@ -204,7 +211,7 @@ module HotGlue
|
|
|
204
211
|
col = full_col.to_s.gsub("=", "").gsub("-", "").to_sym
|
|
205
212
|
|
|
206
213
|
if col.to_s.starts_with?("**") && layout_object[:columns][:fields][col][:form]
|
|
207
|
-
the_output = "<%= render partial: '#{col.to_s.gsub!("**","")}', locals: {#{singular}: #{singular} } %>"
|
|
214
|
+
the_output = "<%= render partial: '#{pickup_partial_path(col.to_s.gsub!("**",""))}', locals: {#{singular}: #{singular} } %>"
|
|
208
215
|
elsif ! layout_object[:columns][:fields][col][:form]
|
|
209
216
|
# omit from show action
|
|
210
217
|
else
|
|
@@ -285,12 +292,18 @@ module HotGlue
|
|
|
285
292
|
"<% if #{plural}.respond_to?(:total_pages) %><%= paginate(#{plural}) %> <% end %>"
|
|
286
293
|
elsif @pagination_style == "will_paginate"
|
|
287
294
|
"<% if #{plural}.respond_to?(:total_pages) %><%= will_paginate(#{plural}) %> <% end %>"
|
|
288
|
-
elsif @pagination_style == "
|
|
295
|
+
elsif @pagination_style == "pagy9"
|
|
289
296
|
if !@layout_strategy == "bootstrap"
|
|
290
297
|
"<%== pagy_nav(@pagy, anchor_string: 'data-turbo-action=\"advance\"') %>"
|
|
291
298
|
else
|
|
292
299
|
"<%== pagy_bootstrap_nav(@pagy, anchor_string: 'data-turbo-action=\"advance\"') %>"
|
|
293
300
|
end
|
|
301
|
+
elsif @pagination_style == "pagy43"
|
|
302
|
+
if @layout_strategy.is_a?(LayoutStrategy::Bootstrap)
|
|
303
|
+
"<%== @pagy.series_nav(:bootstrap) if @pagy && @pagy.pages > 1 %>"
|
|
304
|
+
else
|
|
305
|
+
"<%== @pagy.series_nav if @pagy && @pagy.pages > 1 %>"
|
|
306
|
+
end
|
|
294
307
|
end
|
|
295
308
|
end
|
|
296
309
|
|
|
@@ -321,7 +334,7 @@ module HotGlue
|
|
|
321
334
|
raise "column #{col} not found on the layout data"
|
|
322
335
|
end
|
|
323
336
|
if col.starts_with?("**") && layout_object[:columns][:fields][col][:show]
|
|
324
|
-
the_output = "<%= render partial: '#{col.to_s.gsub!("**","")}', locals: {#{singular}: #{singular} } %>"
|
|
337
|
+
the_output = "<%= render partial: '#{pickup_partial_path(col.to_s.gsub!("**",""))}', locals: {#{singular}: #{singular} } %>"
|
|
325
338
|
elsif ! layout_object[:columns][:fields][col][:show]
|
|
326
339
|
the_output = ""
|
|
327
340
|
elsif eval("#{singular_class}.columns_hash['#{col}']").nil? && !attachments.keys.include?(col) && !related_sets.include?(col)
|
|
@@ -34,7 +34,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
34
34
|
:search_clear_button, :search_autosearch, :include_object_names,
|
|
35
35
|
:stimmify, :stimmify_camel, :hidden_create, :hidden_update,
|
|
36
36
|
:invisible_create, :invisible_update, :phantom_create_params,
|
|
37
|
-
:phantom_update_params, :lazy, :back_link_to_parent
|
|
37
|
+
:phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents
|
|
38
|
+
|
|
38
39
|
# important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
|
|
39
40
|
# so we use namespace_value instead
|
|
40
41
|
|
|
@@ -121,6 +122,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
121
122
|
class_option :phantom_update_params, type: :string, default: nil
|
|
122
123
|
class_option :controller_prefix, type: :string, default: nil
|
|
123
124
|
class_option :code_in_controller, type: :string, default: nil
|
|
125
|
+
class_option :polymorphic_parent, type: :string, default: nil
|
|
124
126
|
|
|
125
127
|
# SEARCH OPTIONS
|
|
126
128
|
class_option :search, default: nil # set or predicate
|
|
@@ -177,7 +179,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
177
179
|
if Gem::Specification.find_all_by_name('pagy').first.version.to_s.split(".").first.to_i <= 9
|
|
178
180
|
@pagination_style = 'pagy9'
|
|
179
181
|
else
|
|
180
|
-
|
|
182
|
+
# warn "Pagy version 43 not yet compatible"
|
|
181
183
|
@pagination_style = 'pagy43'
|
|
182
184
|
end
|
|
183
185
|
elsif Gem::Specification.find_all_by_name('will_paginate').any?
|
|
@@ -260,6 +262,23 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
260
262
|
|
|
261
263
|
setup_attachments
|
|
262
264
|
|
|
265
|
+
# polymorphic parents
|
|
266
|
+
# input = options["polymorphic_parent"]
|
|
267
|
+
# "parent_id[company|vc_firm|press_outlet],thing_id[apple|banana]"
|
|
268
|
+
|
|
269
|
+
if @nested && @nested.split("/").last.include?("(")
|
|
270
|
+
@polymorphic_parents = [@nested.split("/").last[/\(([^)]+)\)/, 1] + "_id"]
|
|
271
|
+
|
|
272
|
+
else
|
|
273
|
+
@polymorphic_parents = []
|
|
274
|
+
# do we need to be able to set these via a config?
|
|
275
|
+
# the use case I've implemented only supports a polymorphic parent in
|
|
276
|
+
# how you build the nest structure (last nested parent)
|
|
277
|
+
# what if there are two or more fields which are polymorphic on the object
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
puts "polymhic_parents: #{@polymorphic_parents}"
|
|
281
|
+
|
|
263
282
|
@exclude_fields = []
|
|
264
283
|
@exclude_fields += options['exclude'].split(",").collect(&:to_sym)
|
|
265
284
|
|
|
@@ -283,6 +302,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
283
302
|
end
|
|
284
303
|
end
|
|
285
304
|
}.flatten.compact.collect(&:to_sym)
|
|
305
|
+
@include_fields += @polymorphic_parents.collect{ |x|
|
|
306
|
+
[x.to_sym, x.to_s.gsub("_id","_type").to_sym]
|
|
307
|
+
}.flatten
|
|
286
308
|
puts "INCLUDED FIELDS: #{@include_fields}"
|
|
287
309
|
end
|
|
288
310
|
|
|
@@ -904,7 +926,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
904
926
|
invisible_create: @invisible_create,
|
|
905
927
|
invisible_update: @invisible_update,
|
|
906
928
|
phantom_search: @phantom_search,
|
|
907
|
-
pagination_style: @pagination_style
|
|
929
|
+
pagination_style: @pagination_style,
|
|
930
|
+
namespace: @namespace,
|
|
931
|
+
controller_build_folder: @controller_build_folder
|
|
908
932
|
)
|
|
909
933
|
elsif @markup == "slim"
|
|
910
934
|
raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
|
|
@@ -932,6 +956,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
932
956
|
|
|
933
957
|
if options["hawk"]
|
|
934
958
|
options['hawk'].split(",").each do |hawk_entry|
|
|
959
|
+
|
|
935
960
|
# format is: abc_id[thing]
|
|
936
961
|
if hawk_entry.include?("{")
|
|
937
962
|
hawk_entry =~ /(.*){(.*)}/
|
|
@@ -941,20 +966,43 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
941
966
|
hawk_to = @auth
|
|
942
967
|
end
|
|
943
968
|
|
|
944
|
-
hawk_scope = key.gsub("_id", "").pluralize
|
|
945
969
|
|
|
946
|
-
|
|
947
|
-
|
|
970
|
+
hawk_scope = key.gsub("_id", "").pluralize
|
|
971
|
+
reflection = eval(singular_class + ".reflect_on_association(:#{key.gsub('_id', '')})")
|
|
972
|
+
raise "Could not find `#{key.gsub('_id', '')}` association; add this to the #{singular_class} class: \nbelongs_to :#{key.gsub('_id', '')} " if reflection.nil?
|
|
973
|
+
|
|
974
|
+
optional = reflection.options[:optional]
|
|
975
|
+
|
|
976
|
+
# if hawk_to.include?(" ")
|
|
977
|
+
# @hawk_keys[key.to_sym] = { bind_to: [hawk_to.gsub(" ", ",")],
|
|
978
|
+
# polymorphic: true,
|
|
979
|
+
# optional: optional }
|
|
980
|
+
|
|
981
|
+
# # hawk_to.start_with?("[")
|
|
982
|
+
# # # Polymorphic hawk: space-separated scopes inside brackets
|
|
983
|
+
# # # e.g. [account.companies account.vc_firms]
|
|
984
|
+
# # raise "#{key} is not a polymorphic association; add `polymorphic: true` to belongs_to :#{key.gsub('_id', '')} in #{singular_class}" unless reflection.options[:polymorphic]
|
|
985
|
+
# # scopes = hawk_to.gsub(/^\[|\]$/, "").split(" ")
|
|
986
|
+
# # @hawk_keys[key.to_sym] = { bind_to: scopes, polymorphic: true, optional: optional }
|
|
987
|
+
# else
|
|
988
|
+
#
|
|
989
|
+
if hawk_to.include?(" ")
|
|
990
|
+
hawk_to.gsub!(" ", ",")
|
|
991
|
+
polymorphic = true
|
|
992
|
+
else
|
|
993
|
+
polymorphic = false
|
|
948
994
|
end
|
|
949
995
|
|
|
950
|
-
|
|
951
|
-
|
|
952
|
-
|
|
996
|
+
@hawk_keys[key.to_sym] = { bind_to: [hawk_to],
|
|
997
|
+
optional: optional ,
|
|
998
|
+
polymorphic: polymorphic}
|
|
999
|
+
|
|
1000
|
+
|
|
953
1001
|
use_shorthand = !options["hawk"].include?("{")
|
|
954
|
-
|
|
955
1002
|
if use_shorthand # only include the hawk scope if using the shorthand
|
|
956
1003
|
@hawk_keys[key.to_sym][:bind_to] << hawk_scope
|
|
957
1004
|
end
|
|
1005
|
+
# end
|
|
958
1006
|
|
|
959
1007
|
end
|
|
960
1008
|
|
|
@@ -1162,7 +1210,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1162
1210
|
|
|
1163
1211
|
def creation_syntax
|
|
1164
1212
|
if @factory_creation.nil? && ! @alt_lookups.any?
|
|
1165
|
-
|
|
1213
|
+
|
|
1214
|
+
res = (@hawk_keys.any? ? "modified_params = hawk_params({#{ hawk_to_ruby(in_controller: true) }}, modified_params)\n " : "") + "@#{singular } = #{ class_name }.new(modified_params)"
|
|
1166
1215
|
elsif @factory_creation.nil? && @alt_lookups.any?
|
|
1167
1216
|
|
|
1168
1217
|
prelookup_syntax = @alt_lookups.collect{|lookup, data|
|
|
@@ -1181,13 +1230,13 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1181
1230
|
#{@factory_creation}
|
|
1182
1231
|
"
|
|
1183
1232
|
res << "\n " + "@#{singular} = factory.#{singular}" unless res.include?("@#{singular} = factory.#{singular}")
|
|
1184
|
-
res << "\n rescue ActiveRecord::RecordInvalid
|
|
1185
|
-
@#{singular} = factory.#{singular}
|
|
1186
|
-
@action = 'new'
|
|
1187
|
-
end"
|
|
1188
|
-
res
|
|
1233
|
+
res << "\n rescue ActiveRecord::RecordInvalid"
|
|
1234
|
+
res << "\n @#{singular} = factory.#{singular}"
|
|
1235
|
+
res << "\n @action = 'new'"
|
|
1189
1236
|
end
|
|
1237
|
+
res
|
|
1190
1238
|
end
|
|
1239
|
+
|
|
1191
1240
|
|
|
1192
1241
|
def formats
|
|
1193
1242
|
[format]
|
|
@@ -1498,13 +1547,14 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1498
1547
|
end
|
|
1499
1548
|
|
|
1500
1549
|
def object_scope
|
|
1501
|
-
if @nested_set.any? && @nested_set.last[:parent_name]
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
|
|
1506
|
-
|
|
1507
|
-
|
|
1550
|
+
if @nested_set.any? && @nested_set.last[:parent_name] && !@nested_set.last[:polymorph_as]
|
|
1551
|
+
if @nested_set.last[:polymorph_as]
|
|
1552
|
+
possible_associations = [@nested_set.last[:parent_name].pluralize]
|
|
1553
|
+
else
|
|
1554
|
+
possible_associations = eval(singular_class).reflect_on_association(( @nested_set.last[:parent_name]).to_sym)
|
|
1555
|
+
.klass.reflect_on_all_associations(:has_many)
|
|
1556
|
+
.to_a
|
|
1557
|
+
end
|
|
1508
1558
|
|
|
1509
1559
|
association = possible_associations.find{|x|
|
|
1510
1560
|
if x.source_reflection
|
|
@@ -1986,7 +2036,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1986
2036
|
res << " @#{plural} = @#{plural}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
|
|
1987
2037
|
elsif @pagination_style == "will_paginate"
|
|
1988
2038
|
res << " @#{plural} = @#{plural}.paginate(page: params[:page], #{ ", per_page: per" if @paginate_per_page_selector })"
|
|
1989
|
-
elsif @pagination_style == "
|
|
2039
|
+
elsif @pagination_style == "pagy9" || @pagination_style == "pagy43"
|
|
1990
2040
|
res << " @pagy, @#{plural} = pagy(@#{plural})"
|
|
1991
2041
|
end
|
|
1992
2042
|
res
|
|
@@ -2006,19 +2056,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
2006
2056
|
|
|
2007
2057
|
def hawk_to_ruby(in_controller: false)
|
|
2008
2058
|
# false for views; true for controller
|
|
2009
|
-
|
|
2010
2059
|
res = @hawk_keys.collect { |k, v|
|
|
2011
|
-
|
|
2012
|
-
bind_to = bind_to_array.collect{|bt|
|
|
2013
|
-
if in_controller
|
|
2014
|
-
bt.gsub(singular, "@#{singular}")
|
|
2015
|
-
else
|
|
2016
|
-
bt
|
|
2017
|
-
end
|
|
2018
|
-
}
|
|
2019
|
-
|
|
2020
|
-
"#{k.to_s}: [#{bind_to.join(".")}]"
|
|
2060
|
+
"#{k}: #{v[:bind_to]}"
|
|
2021
2061
|
}.compact.join(", ")
|
|
2062
|
+
|
|
2022
2063
|
res
|
|
2023
2064
|
end
|
|
2024
2065
|
|
|
@@ -29,14 +29,12 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
29
29
|
def <%= @nested_set[0][:singular] %><% if @god
|
|
30
30
|
next_object = nil
|
|
31
31
|
collect_objects = @nested_set.reverse.collect {|x|
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
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
|
|
36
36
|
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
next_object = eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").class_name
|
|
37
|
+
next_object = eval("#{next_object || class_name}.reflect_on_association(:#{assoc_name})").class_name
|
|
40
38
|
}
|
|
41
39
|
root_object = collect_objects.last
|
|
42
40
|
else
|
|
@@ -204,9 +202,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
204
202
|
end
|
|
205
203
|
<% end %>
|
|
206
204
|
|
|
207
|
-
modified_params = modify_date_inputs_on_params(<% if @update_show_only %>update_<% end %><%= singular_name %>_params.dup<%= controller_update_params_tap_away_magic_buttons %>, <%= current_user_object %>, <%= datetime_fields_list %>)
|
|
208
|
-
|
|
209
|
-
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% end %>
|
|
205
|
+
modified_params = modify_date_inputs_on_params(<% if @update_show_only %>update_<% end %><%= singular_name %>_params.dup<%= controller_update_params_tap_away_magic_buttons %>, <%= current_user_object %>, <%= datetime_fields_list %>)
|
|
206
|
+
|
|
210
207
|
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
|
211
208
|
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :update)<% end %><% end %>
|
|
212
209
|
<% if (@alt_lookups.any?) %>
|
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.7
|
|
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: 2026-01
|
|
11
|
+
date: 2026-06-01 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|