hot-glue 0.6.21.2 → 0.6.23
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 +219 -4
- data/app/helpers/hot_glue/controller_helper.rb +42 -25
- data/lib/generators/hot_glue/fields/association_field.rb +5 -1
- data/lib/generators/hot_glue/fields/float_field.rb +9 -2
- data/lib/generators/hot_glue/layout/builder.rb +6 -3
- data/lib/generators/hot_glue/layout_strategy/bootstrap.rb +2 -0
- data/lib/generators/hot_glue/markup_templates/erb.rb +2 -3
- data/lib/generators/hot_glue/scaffold_generator.rb +88 -28
- data/lib/generators/hot_glue/templates/controller.rb.erb +9 -8
- data/lib/generators/hot_glue/templates/erb/_form.erb +1 -2
- data/lib/generators/hot_glue/templates/erb/_lazy_list.erb +7 -0
- data/lib/generators/hot_glue/templates/erb/_list.erb +8 -5
- data/lib/generators/hot_glue/templates/erb/_show.erb +2 -4
- data/lib/generators/hot_glue/templates/erb/create.turbo_stream.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/edit.erb +13 -11
- data/lib/generators/hot_glue/templates/erb/index.erb +2 -1
- data/lib/hot-glue.rb +29 -36
- data/lib/hotglue/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 342a81dfd2a338859c929f72b0634b6458a8e6f07f037b6d7c22aba2c2259e9e
|
4
|
+
data.tar.gz: 138dab55e50cef822a4ae6c56c32dbb147d3941b65bb38e1a96c3eef1d11d6a5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 29c0d4473cf36ebf0468b463d80ee19c98375b19085a21218f61d7986ac380b48b12acef8b229fa4884902c8d42f4efadc3668e280994c626f5ff6ddf8ae6d30
|
7
|
+
data.tar.gz: e851c22d5484a50a2135d8a6cf3a3e417c40c40af271880589a7513389b2513f9c3a4cef706657ceaf86a3d1204479726674f8feed0acf2b8accb429becf98b3
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -572,6 +572,37 @@ Then, finally the @charge will be loaded
|
|
572
572
|
This is "starfish access control" or "poor man's access control." It works when the current user has several things they can manage, and by extension can manage children of those things.
|
573
573
|
|
574
574
|
|
575
|
+
#### Example #3: Polymorphic Nesting
|
576
|
+
Use `(` and `)` to specify a non-standard upwards relationship from the child, as in the case of a polymorphic belongs_to
|
577
|
+
|
578
|
+
```
|
579
|
+
class Blast
|
580
|
+
has_many :rules, as: :ruleable
|
581
|
+
end
|
582
|
+
|
583
|
+
class Rule
|
584
|
+
# ruleable_id
|
585
|
+
# ruleable_type
|
586
|
+
|
587
|
+
belongs_to :ruleable, polymorphic: true
|
588
|
+
end
|
589
|
+
```
|
590
|
+
|
591
|
+
routes.rb
|
592
|
+
```
|
593
|
+
resources :blasts do
|
594
|
+
resources :rules
|
595
|
+
end
|
596
|
+
```
|
597
|
+
|
598
|
+
`rails generate hot_glue:scaffold Blast --downnest=rules`
|
599
|
+
|
600
|
+
`rails generate hot_glue:scaffold Rules --nested='blast(ruleable)'`
|
601
|
+
|
602
|
+
Notices the relationship from the parent to child is `rules` but from the child to parent, it is `ruleable` instead of `blast`
|
603
|
+
|
604
|
+
|
605
|
+
|
575
606
|
### `--auth=`
|
576
607
|
|
577
608
|
By default, it will be assumed you have a `current_user` for your user authentication. This will be treated as the "authentication root" for the "poor man's auth" explained above.
|
@@ -821,7 +852,8 @@ Notice that each modifiers can be used with specific field types.
|
|
821
852
|
| tinymce | applies to text fields only, be sure to setup TineMCE globally | text fields only | | |
|
822
853
|
| typeahead | turns a foreign key (only) into a searchable typeahead field | foreign keys only | | |
|
823
854
|
| timezone | turns a string (varchar) into a drop down of timezones | foreign keys only | | |
|
824
|
-
|
|
855
|
+
| include_blank | special modifier for association fields, adds include_blank to the created dropdown | |
|
856
|
+
| none | special modifier for using badges |
|
825
857
|
|
826
858
|
Except for "(truthy label)" and "(falsy label)" which use the special syntax, use the modifier _exactly_ as it is named.
|
827
859
|
|
@@ -1277,6 +1309,45 @@ Can now be created with more space (wider) by adding a `+` to the end of the dow
|
|
1277
1309
|
The 'Abcs' portal will display as 5 bootstrap columns instead of the typical 4. (You may use multiple ++ to keep making it wider but the inverse with minus is not supported
|
1278
1310
|
|
1279
1311
|
|
1312
|
+
Polymorphic Downnesting
|
1313
|
+
|
1314
|
+
Here, a `Blast` `has_many :rules, as: :ruleable`
|
1315
|
+
|
1316
|
+
The child object is named `Rule` but it can belong to a Blast or an Agent. (Agent also has a similar has_many for Rules)
|
1317
|
+
|
1318
|
+
`belongs_to :ruleable, polymorphic: true`
|
1319
|
+
|
1320
|
+
We build the blast & agent controllers like so:
|
1321
|
+
|
1322
|
+
bin/rails generate hot_glue:scaffold Blast --downnest='blast_rules(rules)'
|
1323
|
+
bin/rails generate hot_glue:scaffold Agent --downnest='agent_rules(rules)'
|
1324
|
+
|
1325
|
+
Notice that the relationship name is `rules` (not blast_rules), so what goes before the parenthesis is the controller name (with prefix)
|
1326
|
+
What goes inside the controller name is the real relationship name.
|
1327
|
+
|
1328
|
+
For the children, we can't build one controller for the Rule, instead we build one for the `AgentRules` and another for the `BlastRules`
|
1329
|
+
|
1330
|
+
bin/rails generate hot_glue:scaffold Rule --nested='blast(ruleable)' --controller-prefix='Blast'
|
1331
|
+
bin/rails generate hot_glue:scaffold Rule --nested='agent(ruleable)' --controller-prefix='Agent'
|
1332
|
+
|
1333
|
+
(I realize building one child controller for each type of polymorph is tedius, but this is the best solution I could come up with.)
|
1334
|
+
|
1335
|
+
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`
|
1336
|
+
|
1337
|
+
routes.rb
|
1338
|
+
|
1339
|
+
```
|
1340
|
+
resources :agents do
|
1341
|
+
resources :agent_rules
|
1342
|
+
end
|
1343
|
+
|
1344
|
+
resources :blasts do
|
1345
|
+
resources :blast_rules
|
1346
|
+
end
|
1347
|
+
```
|
1348
|
+
|
1349
|
+
|
1350
|
+
|
1280
1351
|
### `--record-scope=`
|
1281
1352
|
|
1282
1353
|
Record scope allows you to apply a model based scope for the controller being generated.
|
@@ -1374,8 +1445,6 @@ called _after authorization_ but _before saving the new record_
|
|
1374
1445
|
(which creates the record, or fails validation).
|
1375
1446
|
Here you can do things like set default values, or modify the params before the record is saved.
|
1376
1447
|
|
1377
|
-
#### `--code-after-create=`
|
1378
|
-
is called after the record is saved (and thus has an id in the case of the create action).
|
1379
1448
|
|
1380
1449
|
#### `--code-before-update=`
|
1381
1450
|
is called in the `update` action _before_ it is saved.
|
@@ -1383,9 +1452,54 @@ is called in the `update` action _before_ it is saved.
|
|
1383
1452
|
#### `--code-after-update=`
|
1384
1453
|
is called in the `update` action _after_ it is saved.
|
1385
1454
|
|
1455
|
+
|
1456
|
+
#### `--code-after-create=`
|
1457
|
+
is called after a new record is saved (and thus has an id).
|
1458
|
+
|
1459
|
+
Here is where you will call operations that depend on the record having an id, like building child table records.
|
1460
|
+
|
1461
|
+
Notice that the next option is inserted in both `new` and `create`, making it the more suitable choice for setting default values.
|
1462
|
+
|
1463
|
+
|
1386
1464
|
#### `--code-after-new=`
|
1387
|
-
is called in the
|
1465
|
+
is called in both the `new` and `create` actions _directly after the .new() call_
|
1388
1466
|
|
1467
|
+
This is a good place to set your created_by user id, like so
|
1468
|
+
|
1469
|
+
`--code-after-new='@email_template.created_by_user = current_user'`
|
1470
|
+
|
1471
|
+
|
1472
|
+
|
1473
|
+
```
|
1474
|
+
def new
|
1475
|
+
@email_template = EmailTemplate.new(crusade: crusade)
|
1476
|
+
@email_template.created_by_user = current_user // <--- YOUR CUSTOM CODE via --code-after-new
|
1477
|
+
|
1478
|
+
authorize @email_template
|
1479
|
+
@action = 'new'
|
1480
|
+
...
|
1481
|
+
```
|
1482
|
+
|
1483
|
+
Notice that a separate hook for code-after-create is also available, but that happens after the save
|
1484
|
+
|
1485
|
+
Using both together `--code-after-new='@email_template.created_by_user = current_user' --code-after-create='@email_template.do_something'`
|
1486
|
+
|
1487
|
+
|
1488
|
+
|
1489
|
+
```
|
1490
|
+
def create
|
1491
|
+
...
|
1492
|
+
@email_template = EmailTemplate.new(modified_params)
|
1493
|
+
@email_template.created_by_user = current_user // <--- YOUR CUSTOM CODE via --code-after-new
|
1494
|
+
|
1495
|
+
authorize @email_template
|
1496
|
+
|
1497
|
+
if @email_template.save
|
1498
|
+
@email_template.do_something // <--- YOUR CUSTOM CODE via --code-after-create
|
1499
|
+
flash[:notice] = "Successfully created #{@email_template.name}"
|
1500
|
+
account.reload
|
1501
|
+
...
|
1502
|
+
```
|
1389
1503
|
|
1390
1504
|
|
1391
1505
|
|
@@ -2032,10 +2146,111 @@ These automatic pickups for partials are detected at build time. This means that
|
|
2032
2146
|
|
2033
2147
|
# VERSION HISTORY
|
2034
2148
|
|
2149
|
+
#### 2025-08-15 - v.0.6.23
|
2150
|
+
|
2151
|
+
• Lazy Lists: Important Breaking Change
|
2152
|
+
|
2153
|
+
All downnested portals now use Turbo's last list feature (frame with `src:` to load the subview via a separate request).
|
2154
|
+
The user sees "Loading" in the box as it is loading. (See `--downnest` and `--nested` sections.)
|
2155
|
+
|
2156
|
+
Unfortunately, this is a partially breaking change in that a parent & child should be rebuilt together on this version.
|
2157
|
+
|
2158
|
+
Whereas before the parent's edit template included the list and passed it the records to render immediately (in the same request)
|
2159
|
+
|
2160
|
+
```
|
2161
|
+
<%= render partial: "agent_rules/list", locals: {agent: @agent, rules: @agent.rules} %>
|
2162
|
+
|
2163
|
+
```
|
2164
|
+
|
2165
|
+
Now, we will render a new partial (from the child's build folder) at `lazy_list` (when the parent is rendering its children)
|
2166
|
+
|
2167
|
+
```
|
2168
|
+
<%= render partial: "agent_rules/lazy_list", locals: {agent: @agent, ...
|
2169
|
+
```
|
2170
|
+
|
2171
|
+
The `lazy_list` itself contains a turbo frame tag with an `src` set to the URL where the list can be loaded, appened with __lazy=1 to let the child controller know not to render the full layout.
|
2172
|
+
|
2173
|
+
|
2174
|
+
```
|
2175
|
+
<%= tag.turbo_frame id: "__agents-list" + ((('__' + nested_for) if defined?(nested_for)) || ""),
|
2176
|
+
src: account_crusade_agents_path(account,crusade) + "?__lazy",
|
2177
|
+
loading: "lazy" do %>
|
2178
|
+
|
2179
|
+
```
|
2180
|
+
|
2181
|
+
In the downnested controller, the children will now suppress the layout when loaded lazy
|
2182
|
+
|
2183
|
+
```
|
2184
|
+
render layout: (params[:__lazy].present? ? false : true)
|
2185
|
+
```
|
2186
|
+
|
2187
|
+
Just remember you must rebuild the parent if you rebuild a child, and you must rebuild ALL the children of any parent that is rebuilt.
|
2188
|
+
|
2189
|
+
|
2190
|
+
• Modify now has an `include_blank` option to add a blank option for associations
|
2191
|
+
|
2192
|
+
|
2193
|
+
`--modify-as=person_id{include_blank}`
|
2194
|
+
|
2195
|
+
Make sure your `belongs_to` association has `optional: true` or else you will get validation errors when you try to save a record with an empty association.
|
2196
|
+
|
2197
|
+
|
2198
|
+
• Fixes cancel button problems related to subviews (no longer necessary to load the edit of the parent in the lazy paradigm)
|
2199
|
+
|
2200
|
+
• Fixes double-entry redisplay problem (second create action would be saved but not show up in UI) due to malformed nested_for
|
2201
|
+
|
2202
|
+
|
2203
|
+
|
2204
|
+
|
2205
|
+
#### 2025-07-28 v0.6.22
|
2206
|
+
|
2207
|
+
|
2035
2208
|
|
2036
2209
|
#### 2025-07-05 v0.6.21
|
2037
2210
|
•Now use new code insertion `--code-after-new` for code that happens directly after `.new()` call. use semicolon (`;`) to create linebreaks; no reason why the factories should insert flash messages
|
2038
2211
|
|
2212
|
+
`--phantom-create-params`
|
2213
|
+
These parameters get added in the strong parameters safelist for the create action
|
2214
|
+
|
2215
|
+
You'll probably wnat to use this along with --code-after-create to check that phanton param
|
2216
|
+
|
2217
|
+
TODO: you have to tap these away yourself
|
2218
|
+
TODO: can they be tapped away automatically if not using a factory
|
2219
|
+
|
2220
|
+
`--phantom-update-params`
|
2221
|
+
These parameters get added in the strong parameters safelist for the update action
|
2222
|
+
|
2223
|
+
`--controller-prefix`
|
2224
|
+
|
2225
|
+
Prefix the controller name, and the cooresponding route & path structure, with this prefix.
|
2226
|
+
For example, using `--controller-prefix='Open'` on a Document build will produce a controller
|
2227
|
+
|
2228
|
+
`OpenDocumentsController`
|
2229
|
+
|
2230
|
+
The controller will still treat the `Document` model as the thing it is building, just a different style of Document named with the prefix.
|
2231
|
+
|
2232
|
+
(To make this meaningful, you'll want to add a `--record-scope` or in some other way differentiate this controller based on its descriptive prefix)
|
2233
|
+
|
2234
|
+
• Polymorphic Downnesting
|
2235
|
+
|
2236
|
+
- `--nested` and `--downnest` can now both accept a param pass in parentheses `(`..`)` to use with polymorphism
|
2237
|
+
|
2238
|
+
See "Polymorphic downnesting" in the downnesting section for an example.
|
2239
|
+
|
2240
|
+
• Magic buttons no longer take up 2 bootstrap columns for each button
|
2241
|
+
|
2242
|
+
• Adds auto-disable to all Delete buttons; use with a `delete_able?` method on the model
|
2243
|
+
|
2244
|
+
• Removes more vestiges of optionalized nesting (which I had implemented 3 years ago!)
|
2245
|
+
|
2246
|
+
I no longer like optionalized nesting, and recommend against it.
|
2247
|
+
|
2248
|
+
Nesting should always be part of the structure, and every route should operate firmly in its nest path.
|
2249
|
+
|
2250
|
+
Use new controller-prefix to make on-off exceptions or with polymorphic children.
|
2251
|
+
|
2252
|
+
• Fixes for localized datetime & time inputs
|
2253
|
+
|
2039
2254
|
• removes duplicitous flash messages in factory context
|
2040
2255
|
|
2041
2256
|
• adds documentation for `--code-before-create`, `--code-after-create`, `--code-before-update`, `--code-after-update` (these features were already implemented)
|
@@ -9,7 +9,7 @@ module HotGlue
|
|
9
9
|
current_timezone
|
10
10
|
|
11
11
|
args = args.merge({class: 'form-control',
|
12
|
-
|
12
|
+
type: 'datetime-local' })
|
13
13
|
|
14
14
|
if !value.nil?
|
15
15
|
args[:value] = date_to_current_timezone(value, current_timezone) + timezonize(current_timezone)
|
@@ -23,8 +23,8 @@ module HotGlue
|
|
23
23
|
def date_field_localized(form_object, field_name, value, **args)
|
24
24
|
|
25
25
|
form_object.text_field(field_name, args.merge({class: 'form-control',
|
26
|
-
|
27
|
-
|
26
|
+
type: 'date',
|
27
|
+
value: value }))
|
28
28
|
end
|
29
29
|
|
30
30
|
def time_field_localized(form_object, field_name, value, **args )
|
@@ -69,18 +69,23 @@ module HotGlue
|
|
69
69
|
end
|
70
70
|
|
71
71
|
def is_dst_now?
|
72
|
-
Time
|
73
|
-
|
74
|
-
|
72
|
+
ActiveSupport::TimeZone['Eastern Time (US & Canada)'].now.dst?
|
73
|
+
end
|
74
|
+
|
75
|
+
def format_timezone_offset(hour, minute)
|
76
|
+
sign = hour < 0 ? "-" : "+"
|
77
|
+
hour_abs = hour.abs.to_s.rjust(2, '0')
|
78
|
+
minute_str = minute.to_s.rjust(2, '0')
|
79
|
+
"#{sign}#{hour_abs}#{minute_str}"
|
75
80
|
end
|
76
81
|
|
77
82
|
def modify_date_inputs_on_params(modified_params, current_user_object = nil, field_list = {})
|
78
83
|
|
79
84
|
use_timezone = if current_user_object.try(:timezone)
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
85
|
+
(ActiveSupport::TimeZone[current_user_object.timezone])
|
86
|
+
else
|
87
|
+
Time.zone
|
88
|
+
end
|
84
89
|
|
85
90
|
|
86
91
|
uses_dst = (current_user_object.try(:locale_uses_dst)) || false
|
@@ -93,18 +98,28 @@ module HotGlue
|
|
93
98
|
field_list.include?(k.to_sym)
|
94
99
|
end
|
95
100
|
|
96
|
-
parsables = {
|
97
|
-
|
101
|
+
parsables = {
|
102
|
+
datetime: "%Y-%m-%d %H:%M %z",
|
103
|
+
time: "%H:%M %z"
|
104
|
+
}
|
105
|
+
|
98
106
|
|
99
107
|
if include_me && params[k].present?
|
100
108
|
if use_timezone
|
101
109
|
natural_offset = use_timezone.formatted_offset
|
102
|
-
hour = natural_offset.split(":").first
|
103
|
-
min = natural_offset.split(":").last
|
104
|
-
hour = hour.to_i - 1 if uses_dst && is_dst_now?
|
110
|
+
hour = natural_offset.split(":").first.to_i
|
111
|
+
min = natural_offset.split(":").last.to_i
|
105
112
|
|
106
|
-
|
113
|
+
hour = hour + 1 if uses_dst && is_dst_now?
|
114
|
+
|
115
|
+
use_offset = format_timezone_offset(hour, min)
|
107
116
|
parse_date = "#{params[k].gsub("T", " ")} #{use_offset}"
|
117
|
+
|
118
|
+
|
119
|
+
Rails.logger.info("use_offset: #{use_offset}")
|
120
|
+
|
121
|
+
Rails.logger.info("parse_date: #{parse_date}")
|
122
|
+
|
108
123
|
# note: as according to https://stackoverflow.com/questions/20111413/html5-datetime-local-control-how-to-hide-seconds
|
109
124
|
# there is no way to set the seconds to 00 in the datetime-local input field
|
110
125
|
# as I have implemented a "seconds don't matter" solution,
|
@@ -117,6 +132,11 @@ module HotGlue
|
|
117
132
|
else
|
118
133
|
parsed_time = Time.strptime(parse_date, parsables[field_list[k.to_sym]])
|
119
134
|
end
|
135
|
+
Rails.logger.info "parsed_time #{parsed_time}"
|
136
|
+
Rails.logger.info "Timezone: #{use_timezone.name}"
|
137
|
+
Rails.logger.info "Offset: #{use_timezone.formatted_offset}"
|
138
|
+
Rails.logger.info "DST? #{uses_dst} | is_dst_now? => #{is_dst_now?}"
|
139
|
+
Rails.logger.info "Final offset used: #{use_offset}"
|
120
140
|
|
121
141
|
params[k] = parsed_time
|
122
142
|
end
|
@@ -229,12 +249,12 @@ module HotGlue
|
|
229
249
|
when 'is_at_exactly'
|
230
250
|
["EXTRACT(HOUR FROM #{field}) = ?
|
231
251
|
AND EXTRACT(MINUTE FROM #{field}) = ? ", search_start.split(":")[0], search_start.split(":")[1]]
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
252
|
+
# when 'is_at_or_after'
|
253
|
+
# ["#{field} = ? OR #{field} > ?", search_start, search_start]
|
254
|
+
# when "is_before_or_at"
|
255
|
+
# ["#{field} = ? OR #{field} < ?", search_end, search_end]
|
256
|
+
# when "is_between"
|
257
|
+
# ["#{field} BETWEEN ? AND ?", search_start, search_end]
|
238
258
|
end
|
239
259
|
end
|
240
260
|
end
|
@@ -265,8 +285,5 @@ module HotGlue
|
|
265
285
|
|
266
286
|
private
|
267
287
|
|
268
|
-
# def server_timezone_offset # returns integer of hours to add/subtract from UTC
|
269
|
-
# Time.now.in_time_zone(Rails.application.config.time_zone).strftime("%z").to_i/100
|
270
|
-
# end
|
271
288
|
end
|
272
289
|
end
|
@@ -154,8 +154,12 @@ class AssociationField < Field
|
|
154
154
|
|
155
155
|
|
156
156
|
|
157
|
+
if modify_as && modify_as[:include_blank]
|
158
|
+
include_blank = ", include_blank: true"
|
159
|
+
end
|
160
|
+
|
157
161
|
(is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
|
158
|
-
" <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, { prompt: true, selected: #{singular}.#{name} }, class: 'form-control'#{data_attr}) %>\n" +
|
162
|
+
" <%= f.collection_select(:#{name}, #{hawked_association}, :id, :#{display_column}, { prompt: true, selected: #{singular}.#{name}#{include_blank} }, class: 'form-control'#{data_attr}) %>\n" +
|
159
163
|
(is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
|
160
164
|
(is_owner ? "\n<% end %>" : "")
|
161
165
|
end
|
@@ -21,14 +21,21 @@ class FloatField < Field
|
|
21
21
|
# end
|
22
22
|
|
23
23
|
def search_field_output
|
24
|
-
""
|
24
|
+
" <div>" +
|
25
|
+
"\n <%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['=', '='], " +
|
26
|
+
"\n ['≥', '≥'], ['>', '>'], " +
|
27
|
+
"\n ['≤', '≤'], ['<', '<']], @q[\'0\']['#{name}_match'] ), {} ," +
|
28
|
+
"\n { class: 'form-control match' } %>"+
|
29
|
+
"\n <%= f.text_field 'q[0][#{name}_search]', {value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 4, class: 'form-control', type: 'number'} %>" +
|
30
|
+
"\n </div>"
|
25
31
|
end
|
26
32
|
|
27
33
|
|
28
34
|
def where_query_statement
|
35
|
+
".where(\"#{name} \#{#{name}_query }\")"
|
29
36
|
end
|
30
37
|
|
31
38
|
def load_all_query_statement
|
32
|
-
|
39
|
+
"#{name}_query = integer_query_constructor(@q['0'][:#{name}_match], @q['0'][:#{name}_search])"
|
33
40
|
end
|
34
41
|
end
|
@@ -60,16 +60,19 @@ module HotGlue
|
|
60
60
|
unless @big_edit
|
61
61
|
# how_many_downnest = downnest_object.size
|
62
62
|
if(!stacked_downnesting)
|
63
|
-
bootstrap_columns = bootstrap_columns - (downnest_object.
|
63
|
+
bootstrap_columns = bootstrap_columns - (downnest_object.size * 4)
|
64
64
|
else
|
65
65
|
bootstrap_columns = bootstrap_columns - 4
|
66
66
|
end
|
67
67
|
|
68
68
|
# downnest_children_width = []
|
69
|
-
|
70
|
-
|
69
|
+
|
70
|
+
|
71
|
+
@downnest_object.each do |child, data|
|
72
|
+
layout_object[:portals][child] = {size: data[:extra_size] + 4}
|
71
73
|
end
|
72
74
|
end
|
75
|
+
|
73
76
|
available_columns = (bootstrap_columns / bootstrap_column_width).floor
|
74
77
|
|
75
78
|
# when set to 2, turns the 12-column grid into a 6-column grid
|
@@ -34,10 +34,12 @@ class LayoutStrategy::Bootstrap < LayoutStrategy::Base
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def column_width
|
37
|
+
|
37
38
|
builder.layout_object[:columns][:size_each]
|
38
39
|
end
|
39
40
|
|
40
41
|
def downnest_portal_column_width(downnest)
|
42
|
+
|
41
43
|
"col-sm-#{ builder.layout_object[:portals][downnest][:size] }"
|
42
44
|
end
|
43
45
|
|
@@ -195,11 +195,11 @@ module HotGlue
|
|
195
195
|
end
|
196
196
|
|
197
197
|
|
198
|
-
the_output = add_spaces_each_line( "\n <
|
198
|
+
the_output = add_spaces_each_line( "\n <div #{@tinymce_stimulus_controller}class='<%= \"alert alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{data_attr} >\n" +
|
199
199
|
add_spaces_each_line( (form_labels_position == 'before' ? (the_label || "") + "<br />\n" : "") +
|
200
200
|
+ field_result +
|
201
201
|
(form_labels_position == 'after' ? ( columns_map[col].newline_after_field? ? "<br />\n" : "") + (the_label || "") : "") , 4) +
|
202
|
-
"\n </
|
202
|
+
"\n </div>\n ", 2)
|
203
203
|
|
204
204
|
|
205
205
|
if hidden_create.include?(col.to_sym) || hidden_update.include?(col.to_sym)
|
@@ -244,7 +244,6 @@ module HotGlue
|
|
244
244
|
def all_line_fields(layout_strategy:,
|
245
245
|
perc_width:)
|
246
246
|
|
247
|
-
|
248
247
|
inline_list_labels = @inline_list_labels || 'omit'
|
249
248
|
columns = layout_object[:columns][:container]
|
250
249
|
|
@@ -30,7 +30,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
30
30
|
:self_auth, :namespace_value, :record_scope, :related_sets,
|
31
31
|
:search_clear_button, :search_autosearch, :include_object_names,
|
32
32
|
:stimmify, :stimmify_camel, :hidden_create, :hidden_update,
|
33
|
-
:invisible_create, :invisible_update
|
33
|
+
:invisible_create, :invisible_update, :phantom_create_params,
|
34
|
+
:phantom_update_params, :lazy
|
34
35
|
# important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
|
35
36
|
# so we use namespace_value instead
|
36
37
|
|
@@ -113,7 +114,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
113
114
|
class_option :new_button_position, type: :string, default: 'above'
|
114
115
|
class_option :downnest_shows_headings, type: :boolean, default: nil
|
115
116
|
class_option :stimmify, type: :string, default: nil
|
116
|
-
|
117
|
+
class_option :phantom_create_params, type: :string, default: nil
|
118
|
+
class_option :phantom_update_params, type: :string, default: nil
|
119
|
+
class_option :controller_prefix, type: :string, default: nil
|
117
120
|
|
118
121
|
# SEARCH OPTIONS
|
119
122
|
class_option :search, default: nil # set or predicate
|
@@ -170,7 +173,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
170
173
|
get_default_from_config(key: :bootstrap_column_width) || 2
|
171
174
|
|
172
175
|
|
173
|
-
|
176
|
+
@controller_prefix = options['controller_prefix']
|
174
177
|
@default_boolean_display = get_default_from_config(key: :default_boolean_display)
|
175
178
|
if options['layout']
|
176
179
|
layout = options['layout']
|
@@ -195,18 +198,25 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
195
198
|
end
|
196
199
|
|
197
200
|
args = meta_args[0]
|
198
|
-
@singular =
|
201
|
+
@singular = args.first.tableize.singularize # should be in form hello_world
|
199
202
|
|
200
203
|
if @singular.include?("/")
|
201
204
|
@singular = @singular.split("/").last
|
202
205
|
end
|
203
206
|
|
204
|
-
@plural = options['plural'] ||
|
207
|
+
@plural = (options['plural'] || args.first.tableize.singularize.pluralize) # respects what you set in inflections.rb, to override, use plural option
|
208
|
+
|
209
|
+
puts "SINGULAR: #{@singular}"
|
210
|
+
puts "PLURAL: #{@plural}"
|
211
|
+
|
212
|
+
|
205
213
|
@namespace = options['namespace'] || nil
|
206
214
|
@namespace_value = @namespace
|
207
|
-
use_controller_name =
|
208
|
-
|
209
|
-
|
215
|
+
use_controller_name = plural.titleize.gsub(" ", "")
|
216
|
+
|
217
|
+
|
218
|
+
@controller_build_name = ((@namespace.titleize.gsub(" ", "") + "::" if @namespace) || "") + (@controller_prefix ? @controller_prefix.titleize : "") + use_controller_name + "Controller"
|
219
|
+
@controller_build_folder = (@controller_prefix ? @controller_prefix.downcase + "_" : "") + use_controller_name.underscore
|
210
220
|
@controller_build_folder_singular = singular
|
211
221
|
|
212
222
|
@auth = options['auth'] || "current_user"
|
@@ -293,6 +303,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
293
303
|
@modify_as[key.to_sym] = {typeahead: 1, nested: nested}
|
294
304
|
elsif $2 == "timezone"
|
295
305
|
@modify_as[key.to_sym] = {timezone: 1, badges: $3}
|
306
|
+
elsif $2 == "include_blank"
|
307
|
+
@modify_as[key.to_sym] = {include_blank: true}
|
296
308
|
elsif $2 == "none"
|
297
309
|
@modify_as[key.to_sym] = {none: 1, badges: $3}
|
298
310
|
else
|
@@ -387,6 +399,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
387
399
|
|
388
400
|
@no_nav_menu = options['no_nav_menu']
|
389
401
|
|
402
|
+
@phantom_create_params = options['phantom_create_params'] || ""
|
403
|
+
@phantom_update_params = options['phantom_update_params'] || ""
|
404
|
+
|
390
405
|
if get_default_from_config(key: :pundit_default)
|
391
406
|
raise "please note the config setting `pundit_default` has been renamed `pundit`. please update your hot_glue.yml file"
|
392
407
|
end
|
@@ -409,11 +424,31 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
409
424
|
|
410
425
|
@downnest_children = [] # TODO: defactor @downnest_children in favor of downnest_object
|
411
426
|
@downnest_object = {}
|
427
|
+
|
412
428
|
if @downnest
|
413
|
-
@downnest_children = @downnest.split(",")
|
414
|
-
|
429
|
+
@downnest_children = @downnest.split(",")
|
430
|
+
|
431
|
+
@downnest_children.each do |child|
|
432
|
+
if child.include?("(")
|
433
|
+
child =~ /(.*)\((.*)\)/
|
434
|
+
child_name, polymorph_as = $1, $2
|
435
|
+
else
|
436
|
+
child_name = child
|
437
|
+
end
|
438
|
+
extra_size = child_name.count("+")
|
439
|
+
|
440
|
+
child_name.gsub!("+","")
|
441
|
+
|
442
|
+
|
443
|
+
@downnest_object[child] = {
|
444
|
+
name: child_name,
|
445
|
+
extra_size: extra_size,
|
446
|
+
polymorph_as: polymorph_as
|
447
|
+
}
|
448
|
+
end
|
415
449
|
end
|
416
450
|
|
451
|
+
|
417
452
|
@include_object_names = options['include_object_names'] || get_default_from_config(key: :include_object_names)
|
418
453
|
|
419
454
|
|
@@ -458,17 +493,26 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
458
493
|
|
459
494
|
if !@nested.nil?
|
460
495
|
@nested_set = @nested.split("/").collect { |arg|
|
461
|
-
|
462
|
-
|
496
|
+
if arg.include?("(")
|
497
|
+
arg =~ /(.*)\((.*)\)/
|
498
|
+
singular, polymorph_as = $1, $2
|
499
|
+
else
|
500
|
+
singular = arg
|
501
|
+
end
|
502
|
+
|
463
503
|
{
|
464
|
-
singular:
|
465
|
-
plural:
|
466
|
-
|
504
|
+
singular: singular,
|
505
|
+
plural: singular.pluralize,
|
506
|
+
polymorph_as: polymorph_as
|
467
507
|
}
|
468
508
|
}
|
469
509
|
puts "NESTING: #{@nested_set}"
|
470
510
|
end
|
471
511
|
|
512
|
+
if @nested_set.any?
|
513
|
+
@lazy = true
|
514
|
+
end
|
515
|
+
|
472
516
|
# related_sets
|
473
517
|
related_set_input = options['related_sets'].split(",")
|
474
518
|
@related_sets = {}
|
@@ -489,6 +533,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
489
533
|
|
490
534
|
# OBJECT OWNERSHIP & NESTING
|
491
535
|
@reference_name = HotGlue.derrive_reference_name(singular_class)
|
536
|
+
|
537
|
+
|
492
538
|
if @auth && @self_auth
|
493
539
|
@object_owner_sym = @auth.gsub("current_", "").to_sym
|
494
540
|
@object_owner_eval = @auth
|
@@ -506,10 +552,11 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
506
552
|
@object_owner_eval = @auth
|
507
553
|
else
|
508
554
|
if @nested_set.any?
|
509
|
-
|
510
|
-
@
|
511
|
-
|
512
|
-
@
|
555
|
+
|
556
|
+
@object_owner_sym = (@nested_set.last[:polymorph_as] || @nested_set.last[:singular]).to_sym
|
557
|
+
|
558
|
+
@object_owner_eval = "#{( @nested_set.last[:singular])}"
|
559
|
+
@object_owner_name = (@nested_set.last[:polymorph_as] || @nested_set.last[:singular])
|
513
560
|
else
|
514
561
|
@object_owner_sym = nil
|
515
562
|
@object_owner_eval = ""
|
@@ -534,7 +581,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
534
581
|
@code_after_update = options['code_after_update']
|
535
582
|
@code_after_new = options['code_after_new']
|
536
583
|
|
537
|
-
buttons_width = ((!@no_edit && 1) || 0) + ((!@no_delete && 1) || 0) + @magic_buttons.
|
584
|
+
buttons_width = ((!@no_edit && 1) || 0) + ((!@no_delete && 1) || 0) + (@magic_buttons.any? ? 1 : 0)
|
538
585
|
|
539
586
|
|
540
587
|
# alt_lookups_entry =
|
@@ -546,6 +593,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
546
593
|
setting =~ /(.*){(.*)}/
|
547
594
|
key, lookup_as = $1, $2
|
548
595
|
|
596
|
+
|
597
|
+
|
549
598
|
if !eval("#{class_name}.reflect_on_association(:#{key.to_s.gsub("_id","")})")
|
550
599
|
raise "couldn't find association for #{key} in the object #{class_name}"
|
551
600
|
end
|
@@ -665,6 +714,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
665
714
|
builder = HotGlue::Layout::Builder.new(generator: self,
|
666
715
|
include_setting: options['include'],
|
667
716
|
buttons_width: buttons_width)
|
717
|
+
|
668
718
|
@layout_object = builder.construct
|
669
719
|
|
670
720
|
|
@@ -1195,7 +1245,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1195
1245
|
|
1196
1246
|
def form_path_edit_helper
|
1197
1247
|
HotGlue.optionalized_ternary(namespace: @namespace,
|
1198
|
-
target:
|
1248
|
+
target: @singular,
|
1249
|
+
prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
|
1199
1250
|
nested_set: @nested_set,
|
1200
1251
|
with_params: false,
|
1201
1252
|
put_form: true,
|
@@ -1204,6 +1255,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1204
1255
|
|
1205
1256
|
def delete_path_helper
|
1206
1257
|
HotGlue.optionalized_ternary(namespace: @namespace,
|
1258
|
+
prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
|
1207
1259
|
target: @singular,
|
1208
1260
|
nested_set: @nested_set,
|
1209
1261
|
with_params: false,
|
@@ -1212,6 +1264,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1212
1264
|
|
1213
1265
|
def edit_path_helper
|
1214
1266
|
HotGlue.optionalized_ternary(namespace: @namespace,
|
1267
|
+
prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
|
1215
1268
|
target: @singular,
|
1216
1269
|
nested_set: @nested_set,
|
1217
1270
|
modifier: "edit_",
|
@@ -1219,6 +1272,16 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1219
1272
|
put_form: true)
|
1220
1273
|
end
|
1221
1274
|
|
1275
|
+
def new_path_name
|
1276
|
+
HotGlue.optionalized_ternary(namespace: @namespace,
|
1277
|
+
target: singular,
|
1278
|
+
prefix: (@controller_prefix ? @controller_prefix.downcase + "_" : ""),
|
1279
|
+
nested_set: @nested_set,
|
1280
|
+
modifier: "new_",
|
1281
|
+
with_params: false)
|
1282
|
+
end
|
1283
|
+
|
1284
|
+
|
1222
1285
|
def path_arity
|
1223
1286
|
res = ""
|
1224
1287
|
if @nested_set.any? && @nested
|
@@ -1239,13 +1302,6 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1239
1302
|
"#{@namespace + "/" if @namespace}#{@controller_build_folder}/list"
|
1240
1303
|
end
|
1241
1304
|
|
1242
|
-
def new_path_name
|
1243
|
-
HotGlue.optionalized_ternary(namespace: @namespace,
|
1244
|
-
target: singular,
|
1245
|
-
nested_set: @nested_set,
|
1246
|
-
modifier: "new_",
|
1247
|
-
with_params: false)
|
1248
|
-
end
|
1249
1305
|
|
1250
1306
|
def nested_assignments
|
1251
1307
|
return "" if @nested_set.none?
|
@@ -1486,6 +1542,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1486
1542
|
res -= %w{_list _line index}
|
1487
1543
|
end
|
1488
1544
|
|
1545
|
+
if @lazy
|
1546
|
+
res << '_lazy_list'
|
1547
|
+
end
|
1548
|
+
|
1489
1549
|
res
|
1490
1550
|
end
|
1491
1551
|
|
@@ -86,6 +86,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
86
86
|
authorize @<%= plural_name %><% elsif @pundit && @pundit_policy_override %>
|
87
87
|
skip_authorization
|
88
88
|
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.index?<% end %>
|
89
|
+
<% if @lazy %>render layout: (params[:__lazy].present? ? false : true)<% end %>
|
89
90
|
rescue Pundit::NotAuthorizedError
|
90
91
|
flash[:alert] = 'You are not authorized to perform this action.'
|
91
92
|
render 'layouts/error'<% end %>
|
@@ -116,6 +117,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
116
117
|
|
117
118
|
<%= controller_attachment_orig_filename_pickup_syntax %>
|
118
119
|
<%= creation_syntax %>
|
120
|
+
<%= @code_after_new ? @code_after_new.gsub(";","\n") + "\n" : "" %>
|
119
121
|
|
120
122
|
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
121
123
|
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :create)<% end %><% end %>
|
@@ -144,14 +146,13 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
144
146
|
rescue Pundit::NotAuthorizedError => e
|
145
147
|
flash[:alert] = "Not authorized."
|
146
148
|
@<%= singular %>.errors.add(:base, e.message)
|
147
|
-
<% unless @display_edit_after_create %>render :create, status: :unprocessable_entity<% else %>redirect_to <%=
|
149
|
+
<% unless @display_edit_after_create %>render :create, status: :unprocessable_entity<% else %>redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
|
148
150
|
top_level: true,
|
149
|
-
target: @
|
151
|
+
target: @plural,
|
150
152
|
nested_set: @nested_set,
|
151
|
-
modifier: 'edit_',
|
152
153
|
with_params: true,
|
153
|
-
instance_last_item:
|
154
|
-
put_form:
|
154
|
+
instance_last_item: false,
|
155
|
+
put_form: false).gsub("(#{singular}", "(@#{singular}") %><% end %>
|
155
156
|
|
156
157
|
<% end %>
|
157
158
|
end
|
@@ -164,7 +165,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
164
165
|
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.show?<% end %>
|
165
166
|
redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
|
166
167
|
target: @singular,
|
167
|
-
top_level:
|
168
|
+
top_level: true,
|
168
169
|
nested_set: @nested_set,
|
169
170
|
modifier: 'edit_',
|
170
171
|
with_params: true,
|
@@ -287,13 +288,13 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
287
288
|
end<% end %><% end %>
|
288
289
|
|
289
290
|
def <%=singular_name%>_params
|
290
|
-
fields = <%= ((fields_filtered_for_strong_params - @show_only) + @magic_buttons.collect{|x| "__#{x}"}).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "#{rs[:association_ids_method]}: []"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
291
|
+
fields = <%= ((fields_filtered_for_strong_params - @show_only) + @magic_buttons.collect{|x| "__#{x}"} + @phantom_create_params.split(",")).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "#{rs[:association_ids_method]}: []"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
291
292
|
params.require(:<%= testing_name %>).permit(fields)
|
292
293
|
end<% if @update_show_only %>
|
293
294
|
|
294
295
|
<% unless @no_edit %>
|
295
296
|
def update_<%=singular_name%>_params
|
296
|
-
fields = <%= ((fields_filtered_for_strong_params - @update_show_only) + @magic_buttons.collect{|x| "__#{x}"}).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "#{rs[:association_ids_method]}: []"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
297
|
+
fields = <%= ((fields_filtered_for_strong_params - @update_show_only) + @magic_buttons.collect{|x| "__#{x}"} + @phantom_update_params.split(",")).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "#{rs[:association_ids_method]}: []"}.join(", ") if @related_sets.any? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>
|
297
298
|
<%= (fields_filtered_for_strong_params - @update_show_only).collect{|col|
|
298
299
|
# TODO : fields not on show only also not invisible should be checked here
|
299
300
|
# for _able? methods and added only when able
|
@@ -2,8 +2,7 @@
|
|
2
2
|
<%= form_fields_html %>
|
3
3
|
|
4
4
|
<div class="<%= @layout_strategy.column_classes_for_button_column %>">
|
5
|
-
<\%= link_to "Cancel", <%=
|
6
|
-
@nested_set.none? ? path_helper_plural : edit_parent_path_helper %>, {class: "btn btn-secondary"} %><% if @no_field_form %>
|
5
|
+
<\%= link_to "Cancel", <%= path_helper_plural %> + (params[:page] ? "?page=" + params[:page] : ""), {class: "btn btn-secondary"} %><% if @no_field_form %>
|
7
6
|
<\%= f.hidden_field "_________" %><% end %>
|
8
7
|
<\%= f.submit "Save", class: "btn btn-primary pull-right" %>
|
9
8
|
</div>
|
@@ -19,19 +19,22 @@
|
|
19
19
|
<% if @downnest_object.any? && !@big_edit %>
|
20
20
|
<% if !@stacked_downnesting %>
|
21
21
|
<%= @layout_strategy.downnest_column_style %>
|
22
|
-
|
23
|
-
|
22
|
+
|
23
|
+
<% @downnest_object.each_with_index do |data,i| %>
|
24
|
+
<% downnest = data[1] %>
|
25
|
+
<div class=" scaffold-col-heading <%= @layout_strategy.downnest_portal_column_width(downnest[:name]) %> <%= @layout_strategy.downnest_column_style %>">
|
24
26
|
<strong>
|
25
|
-
<%= downnest.titleize %>
|
27
|
+
<%= downnest[:name].titleize %>
|
26
28
|
</strong>
|
27
29
|
</div>
|
28
30
|
<% end %>
|
29
31
|
<% else %>
|
30
32
|
<div class=" scaffold-col-heading <%= @layout_strategy.downnest_portal_stacked_column_width %> <%= @layout_strategy.downnest_column_style %>">
|
31
33
|
<%= @layout_strategy.downnest_column_style %>
|
32
|
-
<% @downnest_object.
|
34
|
+
<% @downnest_object.each_with_index do |data,i| %>
|
35
|
+
<% downnest = data[1] %>
|
33
36
|
<strong>
|
34
|
-
<%= downnest.titleize %>
|
37
|
+
<%= downnest[:name].titleize %>
|
35
38
|
</strong>
|
36
39
|
<% end %>
|
37
40
|
</div>
|
@@ -1,7 +1,5 @@
|
|
1
1
|
<%= all_line_fields %>
|
2
2
|
|
3
|
-
|
4
|
-
|
5
3
|
<% if @downnest_children.any? && ! @big_edit %>
|
6
4
|
<% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
|
7
5
|
<% if @stacked_downnesting %><div class="<%= @layout_strategy.downnest_portal_stacked_column_width %> scaffold-downnest" ><% end %>
|
@@ -39,11 +37,11 @@
|
|
39
37
|
|
40
38
|
<% if destroy_action %>
|
41
39
|
<\%= form_with url: <%= delete_path_helper %>, html: {data: {'<%= @ujs_syntax ? 'confirm' : 'turbo-confirm' %>': "Are you sure you want to delete #{ <%= @singular + "." + display_class %> }?" }, style: "display: inline-block;"}, method: :delete do |f| %>
|
42
|
-
<\%= f.submit "Delete".html_safe, class: "delete-<%= singular %>-button btn btn-primary btn-sm" %>
|
40
|
+
<\%= f.submit "Delete".html_safe, class: "delete-<%= singular %>-button btn btn-primary btn-sm", disabled: (<%= @singular %>.respond_to?(:delete_able?) && ! <%= @singular %>.delete_able? ) %>
|
43
41
|
<\% end %>
|
44
42
|
<% end %>
|
45
43
|
|
46
44
|
<% unless @no_edit %>
|
47
|
-
<\%= link_to "Edit <% if @button_icons == 'font-awesome' %><i class='fa fa-1x fa-list-alt'></i><% end %>".html_safe, <%= edit_path_helper
|
45
|
+
<\%= link_to "Edit <% if @button_icons == 'font-awesome' %><i class='fa fa-1x fa-list-alt'></i><% end %>".html_safe, <%= edit_path_helper %> + (params[:page] ? "?page=#{params[:page]}" : ""), <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary btn-sm" %>
|
48
46
|
<% end %>
|
49
47
|
</div>
|
@@ -1,6 +1,6 @@
|
|
1
1
|
<\% if @<%= singular %>.errors.none? %>
|
2
2
|
<\%= turbo_stream.replace "<%= @namespace %>__<%= plural %>-list" + <%= nested_for_turbo_nested_constructor %> do %>
|
3
|
-
<\%= render partial: "list", locals: {<%= plural %>: @<%= plural %><% if @nested_set.any? %>, <%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %>, nested_for:
|
3
|
+
<\%= render partial: "list", locals: {<%= plural %>: @<%= plural %><% if @nested_set.any? %>, <%= @nested_set.collect{|arg| "#{arg[:singular]}: @#{arg[:singular]}"}.join(", ") %>, nested_for: "<%= @nested_set.collect{|arg| "#{arg[:singular]}-\#{@#{arg[:singular]}.id}"}.join("__") %>" <% end %> } %>
|
4
4
|
|
5
5
|
<\% end %>
|
6
6
|
<\% end %>
|
@@ -15,27 +15,29 @@
|
|
15
15
|
<% if @downnest_children.any? && @big_edit %>
|
16
16
|
<div class="container" data-controller="bootstrap-tabbed-nav">
|
17
17
|
<ul class="nav nav-tabs" id="<%= singular + "_downnest_portals" %>" role="tablist">
|
18
|
-
<% @downnest_object.each_with_index do |
|
19
|
-
<%
|
18
|
+
<% @downnest_object.each_with_index do |set, index| %>
|
19
|
+
<% key = set[0]; downnest = set[1] %>
|
20
20
|
<li class="nav-item" role="presentation">
|
21
|
-
<button class="nav-link <%= "active" if index==0 %>" id="<%= downnest %>-tab" data-bs-toggle="tab" data-bs-target="#<%= downnest %>-portal" type="button" role="tab" aria-controls="home" aria-selected="true">
|
22
|
-
<%= downnest.titlecase.pluralize %>
|
21
|
+
<button class="nav-link <%= "active" if index==0 %>" id="<%= downnest[:name] %>-tab" data-bs-toggle="tab" data-bs-target="#<%= downnest[:name] %>-portal" type="button" role="tab" aria-controls="home" aria-selected="true">
|
22
|
+
<%= downnest[:name].titlecase.pluralize %>
|
23
23
|
</button>
|
24
24
|
</li>
|
25
25
|
<% end %>
|
26
26
|
</ul>
|
27
27
|
|
28
28
|
<div class="tab-content" id="myTabContent">
|
29
|
-
<% @downnest_object.each_with_index do |
|
30
|
-
<%
|
31
|
-
<div class="tab-pane fade <%= "show active" if index==0 %>" id="<%= downnest %>-portal" role="tabpanel" aria-labelledby="<%= downnest %>-tab">
|
32
|
-
|
33
|
-
<%
|
29
|
+
<% @downnest_object.each_with_index do |set, index| %>
|
30
|
+
<% key = set[0]; downnest = set[1] %>
|
31
|
+
<div class="tab-pane fade <%= "show active" if index==0 %>" id="<%= downnest[:name] %>-portal" role="tabpanel" aria-labelledby="<%= downnest[:name] %>-tab">
|
32
|
+
|
33
|
+
<% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest[:polymorph_as] || downnest[:name]})") %>
|
34
|
+
<% if downnest_object.nil?; raise "no relationship for downnested portal `#{downnest[:name]}` found on `#{singular_class}`; please check relationship for has_many :#{downnest[:name]} or use ( .. ) to work with polymorphism"; end; %>
|
34
35
|
<% downnest_class = downnest_object.class_name %>
|
35
|
-
<% downnest_object_name =
|
36
|
+
<% downnest_object_name = downnest[:name] %>
|
36
37
|
<% downnest_style = @layout_strategy.downnest_style %>
|
37
38
|
|
38
|
-
<\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/
|
39
|
+
<\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/lazy_list", locals: {<%= @singular %>: @<%= @singular %>, <%= @nested_set.collect{|x| "#{x[:singular]}: @#{x[:singular]}"}.join(", ") %><%= @nested_set.any? ? "," : "" %> nested_for: "<%= (@nested_set).collect{|x| "#{x[:singular]}-" + "\#{" + "@#{x[:singular]}.id}"}.join("__") %><%= "__" if @nested_set.any? %><%= singular %>-#{@<%= @singular %>.id}" } \%>
|
40
|
+
|
39
41
|
</div>
|
40
42
|
<% end %>
|
41
43
|
</div>
|
@@ -6,6 +6,7 @@
|
|
6
6
|
|
7
7
|
<%= @layout_strategy.page_begin %>
|
8
8
|
<\%= render partial: '<%= list_path_partial %>',
|
9
|
-
locals: {<%= plural %>: @<%= plural %>
|
9
|
+
locals: {<%= plural %>: @<%= plural %> <% if @nested_set.any? %>, nested_for: "<%= @nested_set.collect{|n| "#{n[:singular]}-\#{@#{n[:singular]}.id}"}.join("__") %>", <%= @nested_set.collect{|n| "#{n[:singular]}: @#{n[:singular]}"}.join(", ") %><% end %>
|
10
|
+
} \%>
|
10
11
|
<%= @layout_strategy.page_end %>
|
11
12
|
</div>
|
data/lib/hot-glue.rb
CHANGED
@@ -22,18 +22,10 @@ module HotGlue
|
|
22
22
|
end
|
23
23
|
|
24
24
|
|
25
|
-
def self.construct_downnest_object(input)
|
26
|
-
res = input.split(",").map { |child|
|
27
|
-
child_name = child.gsub("+","")
|
28
|
-
extra_size = child.count("+")
|
29
|
-
{child_name => 4+extra_size}
|
30
|
-
}
|
31
|
-
Hash[*res.collect{|hash| hash.collect{|key,value| [key,value].flatten}.flatten}.flatten]
|
32
|
-
end
|
33
|
-
|
34
25
|
def self.optionalized_ternary(namespace: nil,
|
35
26
|
target:,
|
36
27
|
nested_set:,
|
28
|
+
prefix: "", # is this used
|
37
29
|
modifier: "",
|
38
30
|
with_params: false,
|
39
31
|
top_level: false,
|
@@ -43,43 +35,44 @@ module HotGlue
|
|
43
35
|
|
44
36
|
|
45
37
|
if nested_set.nil? || nested_set.empty?
|
46
|
-
return modifier + "#{(namespace + '_') if namespace}#{target}_path" + (("(#{instance_sym}#{target})" if put_form) || "")
|
47
|
-
elsif nested_set[0][:optional] == false
|
38
|
+
return modifier + "#{(namespace + '_') if namespace}#{prefix}#{target}_path" + (("(#{instance_sym}#{target})" if put_form) || "")
|
48
39
|
|
40
|
+
else
|
49
41
|
res = modifier + ((namespace + "_" if namespace) || "") + nested_set.collect{|x|
|
50
42
|
x[:singular] + "_"
|
51
|
-
}.join() + target + "_path" + (("(#{nested_set.collect{
|
43
|
+
}.join() + prefix + target + "_path" + (("(#{nested_set.collect{
|
52
44
|
|x| instance_sym + x[:singular] }.join(",")
|
53
45
|
}#{ put_form ? ',' + (instance_last_item ? "@" : instance_sym) + target : '' })") || "")
|
54
46
|
|
55
47
|
res
|
56
|
-
|
57
|
-
|
48
|
+
# else
|
49
|
+
# raise "optional nested set is deprecated"
|
58
50
|
# copy the first item, make a ternery in this cycle, and recursively move to both the
|
59
51
|
# is present path and the is optional path
|
60
52
|
|
61
|
-
nonoptional = nested_set[0].dup
|
62
|
-
nonoptional[:optional] = false
|
63
|
-
rest_of_nest = nested_set[1..-1]
|
64
|
-
|
65
|
-
is_present_path = HotGlue.optionalized_ternary(
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
is_missing_path = HotGlue.optionalized_ternary(
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
53
|
+
# nonoptional = nested_set[0].dup
|
54
|
+
# nonoptional[:optional] = false
|
55
|
+
# rest_of_nest = nested_set[1..-1]
|
56
|
+
#
|
57
|
+
# is_present_path = HotGlue.optionalized_ternary(
|
58
|
+
# namespace: namespace,
|
59
|
+
# target: target,
|
60
|
+
# modifier: modifier,
|
61
|
+
# top_level: top_level,
|
62
|
+
# with_params: with_params,
|
63
|
+
# put_form: put_form,
|
64
|
+
# nested_set: [nonoptional, *rest_of_nest])
|
65
|
+
|
66
|
+
# is_missing_path = HotGlue.optionalized_ternary(
|
67
|
+
# namespace: namespace,
|
68
|
+
# target: target,
|
69
|
+
# modifier: modifier,
|
70
|
+
# top_level: top_level,
|
71
|
+
# with_params: with_params,
|
72
|
+
# put_form: put_form,
|
73
|
+
# nested_set: rest_of_nest )
|
74
|
+
#
|
75
|
+
# return "#{is_present_path}"
|
83
76
|
end
|
84
77
|
end
|
85
78
|
|
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.23
|
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-08-15 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -115,6 +115,7 @@ files:
|
|
115
115
|
- lib/generators/hot_glue/templates/erb/_edit.erb
|
116
116
|
- lib/generators/hot_glue/templates/erb/_flash_notices.erb
|
117
117
|
- lib/generators/hot_glue/templates/erb/_form.erb
|
118
|
+
- lib/generators/hot_glue/templates/erb/_lazy_list.erb
|
118
119
|
- lib/generators/hot_glue/templates/erb/_line.erb
|
119
120
|
- lib/generators/hot_glue/templates/erb/_list.erb
|
120
121
|
- lib/generators/hot_glue/templates/erb/_nav.html.erb
|