hot-glue 0.4.8.1 → 0.4.9.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: afd7653fa703e1bf60d018a359d175c3f99db44446e727c8e6efcea7076ed856
4
- data.tar.gz: 1796ccdc104e936c5416ef8068b1b148d4038f071822f1d62c24d7c0be97f658
3
+ metadata.gz: b96fed7ffa4bfccbe2dbe0d22e4dc784a70304aebf50e0ef672b2fb30c6f4641
4
+ data.tar.gz: bb0398bf9529ad73c69c7703209a5888081ba0a629376a82880b726d5d74faa6
5
5
  SHA512:
6
- metadata.gz: 5899771864cb198681bec532523d375319885cc65a48ffdc3b783af471fd37cc80c94a3e894cd8374829eef066e2a42fe9d9e6af323561de2198ea562ea8d5fe
7
- data.tar.gz: c86ad53fce047f3ce3e029dcf880cbed981d94f79ff1838a6a87288e141b2a33ac72dca01dbc7760937c7cf463da57d2fb56a0aeba3eb009b1781296019aba33
6
+ metadata.gz: 5064b5d5432f0f7f518b70b61a21b7d98a0182efd73a7e8784009f1e8d381edfa5f64cd6222214aefaebc1d9d30fd4adb4be870bf854fc2e8896d7bc77e66120
7
+ data.tar.gz: 6d88a66a54966f7179f4c041d61670fb799c6bcdddc5a0fc5b3d984011ebc3cabbb5b8713fa05fa534b68a1f07f912f8c1ad8b955be3d0f1281618e2b04f3429
data/.github/FUNDING.yml CHANGED
@@ -1,2 +1 @@
1
- custom: ["https://heliosdev.shop/hot-glue-license?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link",
2
- "https://jfb.teachable.com/p/hot-glue-in-depth-tutorial?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"]
1
+ custom: ["https://jfbcodes.com/p/hot-glue-in-depth-tutorial?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"]
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.4.8)
4
+ hot-glue (0.4.9.1)
5
5
  ffaker (~> 2.16)
6
6
  kaminari (~> 1.2)
7
7
  rails (> 5.1)
data/README.md CHANGED
@@ -3,32 +3,34 @@
3
3
 
4
4
  Hot Glue is a Rails scaffold builder for the Turbo era. It is an evolution of the admin-interface style scaffolding systems of the 2010s ([activeadmin](https://github.com/activeadmin/activeadmin), [rails_admin](https://github.com/sferik/rails_admin), and [active_scaffold](https://github.com/activescaffold/active_scaffold)).
5
5
 
6
- Using Turbo-Rails and Hotwire (default in Rails 7) you get a lightning-fast out-of-the-box CRUD building experience.
6
+ Using Turbo-Rails and Hotwire (default in Rails 7) you get a lightning-fast out-of-the-box CRUD-building experience.
7
7
 
8
- Every page displays only a list view: new and edit operations happen as 'edit-in-place', so the user never leaves the page.
8
+ Every page displays only a list view: new and edit operations happen as 'edit-in-place,' so the user never leaves the page.
9
9
 
10
- Because all page navigation is Turbo's responsibilty, everything plugs & plays nicely into a Turbo-backed Rails app.
10
+ Because all page navigation is Turbo's responsibility, everything plugs & plays nicely into a Turbo-backed Rails app.
11
11
 
12
- Alternatively, you can use this tool to create a Turbo-backed *section* of your Rails app-- like an admin interface -- while still treating the rest of the Rails app as an API or building out other features by hand.
12
+ Alternatively, you can use this tool to create a Turbo-backed *section* of your Rails app -- such as an admin interface -- while still treating the rest of the Rails app as an API or building out other features by hand.
13
13
 
14
- It will read your relationships and field types to generate your code for you, leaving you with a 'sourdough starter' to work from. If you modify the generated code, you're on your own if you want to preserve your changes and also re-generate scaffold after adding fields.
14
+ It will read your relationships and field types to generate your code for you, leaving you with a 'sourdough starter' to work from. If you modify the generated code, you're on your own if you want to preserve your changes and also re-generate scaffolding after adding fields.
15
15
 
16
16
  By default, it generates code that gives users full control over objects they 'own' and by default it spits out functionality giving access to all fields.
17
17
 
18
- Hot Glue generates functionality that's quick and dirty. It lets you be crafty. As with a real hot glue gun, use with caution.
18
+ Hot Glue generates functionality that is quick and dirty. It lets you be crafty. As with a real glue gun, use it with caution.
19
19
 
20
20
  * Build plug-and-play scaffolding mixing generated ERB with the power of Hotwire and Turbo-Rails
21
- * Everything edits-in-place (unless you use `--big-edit`, then it won't)
22
- * Automatically Reads Your Models (make them AND migrate your DB before building your scaffolding!)
23
- * Excellent for CREATE-READ-UPDATE-DELETE (CRUD), lists with pagination (coming soon: searching & sorting)
21
+ * Everything edits-in-place (unless you use `--big-edit`)
22
+ * Automatically reads your models (make them AND migrate your database before building your scaffolding!)
23
+ * Excellent for CREATE-READ-UPDATE-DELETE (CRUD), lists with pagination
24
24
  * Great for prototyping, but you should learn Rails fundamentals first.
25
25
  * 'Packaged' with Devise, Kaminari, Rspec, FontAwesome
26
26
  * Create system specs automatically along with the generated code.
27
27
  * Nest your routes model-by-model for built-in poor man's authentication.
28
28
  * Throw the scaffolding away when your app is ready to graduate to its next phase.
29
29
 
30
- # Hot Glue Tutorial 
31
- ## [GET THE COURSE TODAY (includes Hot Glue License)](https://jfbcodes.com/courses/hot-glue-in-depth-tutorial/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) **only $60 USD!**
30
+
31
+ # Get Hot Glue
32
+ ## [Licence Only Option Now Available](https://heliosdev.shop/p/hot-glue/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) **only $50 USD!**
33
+ ## [GET THE COURSE TODAY (includes Licence)](https://jfbcodes.com/courses/hot-glue-in-depth-tutorial/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) **only $60 USD!**
32
34
 
33
35
  | | |
34
36
  | ------------- | ------------- |
@@ -62,10 +64,13 @@ There are two ways to create new apps on Rails 7: With or without ImportMap. The
62
64
 
63
65
  `rails new --css=bootstrap --javascript=webpack --database=postgresql`
64
66
 
65
- Confirm that both Stimulus and Turbo are working. For the quick step-by-step to help you confirm
66
- that both Stimulus and Turbo are working for your new JSBundling-Rails/CSSBunlding-Rails setup [see this post](https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-new-app-with-js-bundling-css-bundling/).
67
+ Confirm that both Stimulus and Turbo are working.
68
+
69
+ **If using JSBundling, make sure to use the new `bin/dev rails` instead of the old `rails server` or else your Webpack will not compile.**
70
+
71
+ For the quick step-by-step guide to help you confirm that both Stimulus and Turbo are working for your new JSBundling-Rails/CSSBunlding-Rails setup [see this post](https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-new-app-with-js-bundling-css-bundling/).
67
72
 
68
- (Note that Bootstrap is optional for Hot Glue. Here, I am just showing you the default isntallation for simplicity.)
73
+ (Note that Bootstrap is optional for Hot Glue. Here, I am just showing you the default installation for simplicity.)
69
74
 
70
75
  For the old method of installing Bootstrap [see this post](https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-7-bootstrap/)
71
76
 
@@ -87,26 +92,20 @@ gem 'ffaker'
87
92
  ## 3. HOTGLUE INSTALLER
88
93
  Add `gem 'hot-glue'` to your Gemfile & `bundle install`
89
94
 
90
- Purchase a license at https://heliosdev.shop/hot-glue-license
95
+ Purchase a license at https://heliosdev.shop/p/hot-glue
91
96
 
92
97
  During in installation, you MUST supply a `--layout` flag.
93
98
 
94
- ### `--layout` flag (NOTE: haml and slim are no longer supported at this time)
95
- Here you will set up and install Hot Glue for the first time. It will install a config file that will save two preferences: layout (hotglue or bootstrap) and markup (erb or haml or slim).
99
+ ### `--layout` flag (only two options: `hotglue` or `bootstrap`; default is `bootstrap`)
100
+ Here you will set up and install Hot Glue for the first time.
96
101
 
97
- Once you run the installer, the installer will save what you set it to in `config/hot_glue.yml`. Newly generated scaffolds will use these two settings, but you can modify them just by modifying the config file (you don't need to re-run the installer)
102
+ It will install a config file that will save two preferences: layout (`hotglue` or `bootstrap`)
98
103
 
99
- If you do NOT specify `--layout=bootstrap`, then `hotglue` will be assumed. When constructing scaffold with bootstrap layout (at this time Hot Glue peeks into config/hot_glue.yml to see what you've set there), your views come out with divs that have classes like .container-fluid, .row, and .col. You'll need to install Bootstrap separately, any way you like, but jQuery is not required as Hot Glue does not rely on jQuery-dependant Bootstrap features.
104
+ The installer will create `config/hot_glue.yml`.
100
105
 
101
106
 
102
- If instead you install Hot Glue (or switch the setting) using the default layout mode (`--layout=hotglue`),
103
- your scaffolding will be built using no-Bootstrap syntax: It has its own syntax with classes like
104
- `.scaffold-container`,
105
- `.scaffold-list`,
106
- `.scaffold-row`, and
107
- `.scaffold-cell`
108
-
109
- During the installation, if your `--layout` flag is left unspecified or set to `hotglue` you must also pass `--theme` flag.
107
+ ### `--theme` flag
108
+ During the installation, **if** your `--layout` flag is set to `hotglue` you must also pass `--theme` flag.
110
109
 
111
110
  the themes are:
112
111
  • like_mountain_view (Google)
@@ -114,25 +113,17 @@ the themes are:
114
113
  • like_bootstrap (bootstrap 4 copy)
115
114
  • dark_knight (_The Dark Night_ (2008) inspired)
116
115
  • like_cupertino (modern Apple-UX inspired)
117
- • gradeschool (spiral bound/lined notebook inspired)
118
-
119
- Please note that the scaffold is ** built with different market up for boostrap**, so you cannot switch between the Bootstrap and Hotglue layouts without rebuilding the scaffold.
120
-
121
- (On the other hand, if you build within the Hotglue layout, all of the Hotglue theme files CAN be swapped out without rebuilding the scaffold.)
122
116
 
123
- The themes are just SCSS files installed into app/assets/stylesheets. You can tweak or modify or remove them after they get installed.
124
117
 
118
+ ### `--markup` flag (NOTE: haml and slim are no longer supported at this time)
125
119
 
126
- ### `--markup` flag
120
+ default is `erb`. IMPORTANT: As of right now, HAML and SLIM are not currently supported so the only option is also the default `erb`.
127
121
 
128
- default is `erb`. IMPORTANT: As of right now, I am only supporting & building against ERB. HAML and SLIM are not currently supported.
129
122
 
130
-
131
- ## 3. RUN HOT-GLUE INSTALL:
132
123
  ### example installing ERB using Bootstrap layout:
133
124
  `rails generate hot_glue:install --markup=erb --layout=bootstrap`
134
125
 
135
- ### Example installing HAML using Hot Glue layout and the 'like_mountain_view' (Gmail-inspired) theme:
126
+ ### Example installing using Hot Glue layout and the 'like_mountain_view' (Gmail-inspired) theme:
136
127
  `rails generate hot_glue:install --markup=erb --layout=hotglue --theme=like_mountain_view`
137
128
 
138
129
  The Hot Glue installer did several things for you in this step. Examine the git diffs or see 'Hot Glue Installer Notes' below.
@@ -152,11 +143,11 @@ https://github.com/FortAwesome/font-awesome-sass
152
143
 
153
144
  Add to your Gemfile
154
145
 
155
- As of 2022-01-26 Devise for Rails 7 is still not released so you must use **main branch**, like so:
146
+ As of now, Devise for Rails 7 is still not released so you must use **main branch**, like so:
156
147
 
157
148
  `gem 'devise', branch: 'main', git: 'https://github.com/heartcombo/devise.git'`
158
149
 
159
- (If you are on Rails 6, you must do ALL of the steps in the Legacy Setup steps. Be sure not to skip **Legacy Step #5** (below))
150
+ (If you are on Rails 6, you must do ALL of the steps in the Legacy Setup steps. Be sure not to skip **Legacy Step #5** below)
160
151
 
161
152
  For Rails 7, be sure you are on the main branch of devise above and your logins should work. (The previously necessary step of disabling turbo shown in Legacy Step #5 is no longer needed. )
162
153
 
@@ -217,7 +208,7 @@ this may not have been automatically applied by the installer.
217
208
  #### Hot Glue switched Capybara from RACK-TEST to HEADLESS CHROME
218
209
 
219
210
  - By default Capybara is installed with :rack_test as its driver.
220
- - This does not support Javascript, and the code from Hot Glue IS NOT fallback compatible-- it will not work on non-Javascript browsers.
211
+ - This does not support Javascript. Hot Glue is not targeted for fallback browsers.
221
212
  - From the [Capybara docs](https://github.com/teamcapybara/capybara#drivers):
222
213
  ```
223
214
  By default, Capybara uses the :rack_test driver, which is fast but limited: it does not support JavaScript
@@ -312,7 +303,7 @@ end
312
303
 
313
304
  ### `--nested=`
314
305
 
315
- This object is nested within another tree of objects, and there is a nested route in your `routes.rb` file. When specifying the parent(s), be sure to use **singular case**.
306
+ This object is nested within another tree of objects, and there is a nested route in your `routes.rb` file with the specified parent controllers above this controller. When specifying the parent(s), be sure to use **singular case**.
316
307
 
317
308
  #### Example #1: One-level Nesting
318
309
  Invoice `has_many :lines` and a Line `belongs_to :invoice`
@@ -373,16 +364,44 @@ Then, finally the @charge will be loaded
373
364
 
374
365
  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.
375
366
 
367
+
368
+ #### Optionalized Nested Parents
369
+
370
+ Add `~` in front of any nested parameter (any parent in the `--nested` list) you want to make optional. This creates a two-headed controller: It can operate with or without that optionalized parameter.
371
+
372
+ This is an advanced feature. To use, **make duplicative routes to the same controller**. You can only use this feature with Gd controller.
373
+
374
+ Specify your controller *twice* in your routes.rb. Then, in your `--nested` setting, add `~` to any nested parent you want to **make optional**. "Make optional" means the controller will behave as-if it exists in two places: once, at the normal nest level. Then the same controller will 'exist' again one-level up in your routes. **If the route has sub-routes, you'll need to re-specify the entire subtree also**.
375
+ ```
376
+ namespace :admin
377
+ resources :users do
378
+ resources :invoices
379
+ end
380
+ resources :invoices
381
+ end
382
+ ```
383
+
384
+ Even though we have two routes pointed to **invoices**, both will go to the same controller (`app/controllers/admin/invoices_controller.rb`)
385
+
386
+ ```
387
+ rails generate hot_glue:scaffold User --namespace=admin --gd
388
+ rails generate hot_glue:scaffold Invoice --namespace=admin --gd --nested=~users
389
+ ```
390
+ Notice for the Invoice build, the parent user is *optionalized* (not 'optional'-- optionalized: to be made so it can be made optional).
391
+
392
+ The Invoices controller, which is a Gd controller, will load the User if a user is specified in the route (`/admin/users/:user_id/invoices/`). It will ALSO work at `/admin/invoices` and will switch back into loading directly from the base class when routed without the parent user.
393
+
394
+
376
395
 
377
396
  ### `--auth=`
378
397
 
379
398
  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.
380
399
 
381
- The poor man's auth presumes that object graphs have only one natural way to traverse them (that is, one primary way to traverse them), and that all relationships infer that a set of things or their descendants are granted access to me for reading, writing, updating, and deleting.
400
+ The poor man's auth presumes that object graphs have only one natural way to traverse them (that is, one primary way to traverse them), and that all relationships infer that a set of things or their descendants are granted access to "me" for reading, writing, updating, and deleting.
382
401
 
383
402
  Of course this is a sloppy way to do access control, and can easily leave open endpoints your real users shouldn't have access to.
384
403
 
385
- When you display anything built with the scaffolding, we assume the `current_user` will have `has_many` association that matches the pluralized name of the scaffold. In the case of nesting, we will automatically find the nested objects first, then continue down the nest chain to find the target object. In this way, we know that all object are 'anchored' to the logged-in user.
404
+ When you display anything built with the scaffolding, Hot Glue assumes the `current_user` will have `has_many` association that matches the pluralized name of the scaffold. In the case of nesting, we will automatically find the nested objects first, then continue down the nest chain to find the target object. This is how Hot Glue assumes all object are 'anchored' to the logged-in user. (As explained in the `--nested` section.)
386
405
 
387
406
  If you use Devise, you probably already have a `current_user` method available in your controllers. If you don't use Devise, you can implement it in your ApplicationController.
388
407
 
@@ -396,28 +415,6 @@ It is also presumed that when viewing their own dashboard of things, the user wi
396
415
 
397
416
  If you supply nesting (see below), your nest chain will automatically begin with your auth root object (see nesting)
398
417
 
399
- #### Optionalized Nested Parents
400
-
401
- Add `~` in front of any nested parameter (any parent in the `--nest` list) you want to make optional. This creates a two-headed controller: It can operate with or without that optionalized parameter.
402
-
403
- This is an advanced feature is to use two duplicitous routes to the same controller. You can only use this feature with Gd controller. To use, specify your controller *twice* in your routes.rb. Then, in your `--nest` setting, add `~` to any nested parent you want to **make optional**. "Make optional" means the controller will behave as-if it exists in two places: once, at the normal nest level. Then the same controller will 'exist' again one-level up in your routes. **If the route has sub-routes, you'll need to re-specify the entire subtree also**.
404
- ```
405
- namespace :admin
406
- resources :users do
407
- resources :invoices
408
- end
409
- resources :invoices
410
- end
411
- ```
412
- Hot Glue will build the scaffolding once for users and once again for invoice. Even though we have two routes pointed to invoices,
413
- ```
414
- rails generate hot_glue:scaffold User --namespace=admin --gd --downnest=invoices
415
- rails generate hot_glue:scaffold Invoice --namespace=admin --gd --nest=~users
416
- ```
417
- Notice for the Invoice build, the parent user is *optionalized* (not 'optional'-- optionalized: to be made so it can be made optional). The Invoices controller, which is a Gd controller, will load the User if a user is specified in the route (`/admin/users/:user_id/invoices/`). It will ALSO work at `/admin/invoices` and will switch back into loading directly from the base class when routed this way.
418
-
419
-
420
-
421
418
 
422
419
  ### `--auth_identifier=`
423
420
 
@@ -450,6 +447,8 @@ The default (do not pass `auth_identifier=`) will match the `auth` (So if you us
450
447
 
451
448
 
452
449
  `rails generate hot_glue:scaffold Thing --auth=current_account --auth_identifier=login`
450
+
451
+
453
452
  In this example, the controller produced with:
454
453
  ```
455
454
  before_action :authenticate_login!
@@ -460,11 +459,12 @@ However, the object graph anchors would continue to start from current_account.
460
459
  ```
461
460
 
462
461
  Use empty string to **turn this method off**:
462
+
463
463
  `rails generate hot_glue:scaffold Thing --auth=current_account --auth_identifier=''`
464
464
 
465
465
  In this case a controller would be generated that would have NO before_action to authenticate the account, but it would still treat the current_account as the auth root for the purpose of loading the objects.
466
466
 
467
- Please note that this example would product non-functional code, so you would need to manually fix your controllers to make sure `current_account` is available to the controller.
467
+ Please note that this example would produce non-functional code, so you would need to manually fix your controllers to make sure `current_account` is available to the controller.
468
468
 
469
469
 
470
470
  ### `--plural=`
@@ -475,14 +475,14 @@ You don't need this if the pluralized version is just + "s" of the singular vers
475
475
  ### `--exclude=`
476
476
  (separate field names by COMMA)
477
477
 
478
- By default, all fields are included unless they are on the exclude list. (The default for the exclude list is `id`, `created_at`, and `updated_at` so you don't need to exclude those-- they are added.)
478
+ By default, all fields are included unless they are on the default exclude list. (The default exclude list is `id`, `created_at`, `updated_at`, `encrypted_password`, `reset_password_token`, `reset_password_sent_at`, `remember_created_at`, `confirmation_token`, `confirmed_at`, `confirmation_sent_at`, `unconfirmed_email`.)
479
479
 
480
- If you specify an exclude list, those and the default excluded list will be excluded.
480
+ If you specify any exclude list, those excluded **and** the default exclude list will be excluded. (If you need any of the fields on the default exclude list, you must use `--include` instead.)
481
481
 
482
482
 
483
483
  `rails generate hot_glue:scaffold Account --exclude=password`
484
484
 
485
- (The default excluded list is: :id, :created_at, :updated_at, :encrypted_password, :reset_password_token, :reset_password_sent_at, :remember_created_at, :confirmation_token, :confirmed_at, :confirmation_sent_at, :unconfirmed_email. If you want to edit any fields with the same name, you must use the include flag instead.)
485
+ (The default excluded list is: If you want to edit any fields with the same name, you must use the include flag instead.)
486
486
 
487
487
 
488
488
  ### `--include=`
@@ -494,46 +494,50 @@ If you specify an include list, it will be treated as a whitelist: no fields wil
494
494
 
495
495
  You may not specify both include and exclude.
496
496
 
497
- Include setting is affected by both specified grouping and smarty layouts, explained below.
497
+ Include setting is affected by both specified grouping mode and smart layouts, explained below.
498
498
 
499
499
 
500
500
  #### Specified Grouping Mode
501
501
 
502
502
  To specify grouped columns, separate COLUMNS by a COLON, then separate fields with commas. Specified groupings work like smart layouts (see below), except you drive which groupings make up the columns.
503
503
 
504
- (Smarty layouts, below, achieves the same effect but automatically groups your fields into a smart number of columns. )
504
+ (Smart layouts, below, achieves the same effect but automatically group your fields into a smart number of columns.)
505
505
 
506
506
  If you want to group up fields together into columns, use a COLON (`:`) character to specify columns.
507
507
 
508
508
  Your input **may** have a COLON at the end of it, but otherwise your columns will made **flush left**.
509
509
 
510
- Without specified grouping (and not using smart layout), no group will happen, so these two fields would display in two columns:
511
- `--include=api_id,api_key`
512
-
513
- With a trailing colon you would be specifying the grouping. You're telling Hot Glue to make the two fields into column #1. (There is no other column.)
514
- `--include=api_id,api_key:`
510
+ Without specified grouping (and not using smart layout), no grouping will happen. So these two fields would display in two (small, 1-column Bootstrap) columns:
511
+
512
+ `--include=first,last`
515
513
 
514
+ With a **trailing colon** you switch Hot Glue into specified grouping mode. You're telling Hot Glue to make the two fields into column #1. (There is no other column.)
515
+ `--include=first,last:`
516
516
 
517
- If, for example, you wanted to put the `name` field into column #1 and then the api_id and api_key into column #2, you would use:
518
- `--include=name:api_id,api_key`
517
+ Hot Glue also happens to know that, for example, when you say "one column" you really want _one visual_ column made up of the available Bootstrap columns. For example, with 1 child portal (4) + the default edit/create buttons (2), you would have 6 remaining bootstrap columns (2+4+6=12). With 6 remaining Bootstrap columns Hot Glue will make 1 _visual colum_ into a 6-column Bootstrap column.
519
518
 
519
+ If, for example, you wanted to put the `email` field into column #1 and then the `first` and `last` into column #2, you would use:
520
+ `--include=email:first,last`
520
521
 
522
+ Assuming we have the same number of columns as the above example (6), Hot Glue knows that you now have 2 _visual columns_. It then gives each visual column 3-colum bootstrap columns, which makes your layout into a 3+3+4+2=12 Bootstrap layout.
521
523
 
522
- Specifying any colon in your include syntax switches the builder into specified grouping mode. The effect will be that the fields will be stacked together into nicely fit columns. (This will look confusing if your user expect an Excel-like interface.)
524
+ **Specifying any colon in your include syntax switches the builder into specified grouping mode.**
525
+
526
+ The effect will be that the fields will be stacked together into nicely fit columns. (This will look confusing if your end-user is expecting an Excel-like interface.)
523
527
 
524
- With Bootstrap in specified grouping or smart layout mode, it automatically attempts to fit everything into 12-columns.
528
+ With Hot Glue in specified grouping or smart layout mode, it automatically attempts to fit everything into Bootstrap 12-columns.
525
529
 
526
- Using Bootstrap with neither specified grouping nor smart layouts may make 12 columns, which will produce strange result. (Bootstrap is not designed to work with, for example, a 13-column layout.)
530
+ Using Bootstrap with neither specified grouping nor smart layouts may make more than 12 columns, which will produce strange results. (Bootstrap is not designed to work with, for example, a 13-column layout.)
527
531
 
528
- You should typically either specify your grouping or use smart layouts when building with Bootstrap, but if your use case does not fit the stacking feature you can specify neither and then you may have deal with the over-stuffed layouts as explained above.
532
+ You should typically either specify your grouping or use smart layouts when building with Bootstrap, but if your use case does not fit the stacking feature you can specify neither flag and then you may then have to deal with the over-stuffed layouts as explained.
529
533
 
530
534
 
531
535
 
532
- ### `--smart-layout` mode (automatic grouping) (default: false)
536
+ ### `--smart-layout` (also known as automatic grouping)
533
537
 
534
538
  Smart layouts are like specified grouping but Hot Glue does the work of figuring out how many fields you want in each column.
535
539
 
536
- It will concatinate your fields into groups that will fit into the Bootstraps 12-column grid.
540
+ It will concatinate your fields into groups that will fit into the Bootstrap's 12-column grid.
537
541
 
538
542
  The effect will be that the fields will be stacked together into nicely fit columns.
539
543
 
@@ -541,7 +545,7 @@ The effect will be that the fields will be stacked together into nicely fit colu
541
545
 
542
546
  **If your customer is used to Excel, this feature will confuse them.**
543
547
 
544
- Also, this feature will **probably not** be supported by the SORTING (not yet implemented; TBD). I'm not really sure it makes sense to build a non-columnar layout with sorting, so I think I **probably won't support smart layouts** if you want sorting. (You will be forced to choose between the two which I think makes sense.)
548
+ Also, this feature will **probably not** be supported by the SORTING (not yet implemented). (You will be forced to choose between the two which I think makes sense.)
545
549
 
546
550
  The layout builder works from right-to-left and starts with 12, the number of Bootstrap's columns.
547
551
 
@@ -553,7 +557,7 @@ If you're keeping track, that means we may have used 6 to 8 out of our Bootstrap
553
557
 
554
558
  If we have 2 downnested portals and only the default buttons, that uses 10 out of 12 Bootstrap columns, leaving only 2 bootstrap columns for the fields.
555
559
 
556
- THe layout builder takes the number of columns left and then distributes the feilds 'evenly' among them. However, note that order specified translates to up-to-down within the column, and then left-to-right across the columns, like so:
560
+ The layout builder takes the number of columns remaining and then distributes the feilds 'evenly' among them. However, note that order specified translates to up-to-down within the column, and then left-to-right across the columns, like so:
557
561
 
558
562
  A D G
559
563
 
@@ -563,7 +567,7 @@ C F I
563
567
 
564
568
  This is what would happen if 9 fields, specified in the order A,B,C,D,E,F,G,H,I, were distributed across 3 columns.
565
569
 
566
- (If you had a number of fields that wasn't easily divisible by the number of columns, it would leave the final column a few fields short of the others.)
570
+ (If you had a number of fields that wasn't easily divisible by the number of columns, it would leave the final column one or a few fields short of the others.)
567
571
 
568
572
 
569
573
 
@@ -622,7 +626,11 @@ Automatically create subviews down your object tree. This should be the name of
622
626
  You will need to build scaffolding with the same name for the related object as well. On the list view, the object you are currently building will be built with a sub-view list of the objects related from the given line.
623
627
 
624
628
  The downnested child table (not to be confused with this object's `--nested` setting, where you are specifying this object's _parents_) is called a **child portal**. When you create a record in the child portal, the related record is automatically set to be owned by its parent (as specified by `--nested`). For an example, see the [v0.4.7 release notes](https://github.com/jasonfb/hot-glue/releases/tag/v0.4.7).
625
-
629
+
630
+ Can now be created with more space (wider) by adding a `+` to the end of the downnest name
631
+ - e.g. `--downnest=abc+,xyz`
632
+
633
+ 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
626
634
 
627
635
 
628
636
 
@@ -660,32 +668,41 @@ Omits pagination. (All list views have pagination by default.)
660
668
 
661
669
  ### `--no-list`
662
670
 
663
- Omits list action. Only makes sense to use this if you are create a view where you only want the create button you want to navigate to the update screen alternative ways.
671
+ Omits list action. Only makes sense to use this if want to create a view where you only want the create button or to navigate to the update screen alternative ways. (The new/create still appears, as well the edit, update & destroy actions are still created even though there is no natural way to navigate to them.)
672
+
664
673
 
674
+ ### `--no-list-label`
665
675
 
666
- ### `--no-list-labels`
676
+ Omits list LABEL itself above the list. (Do not confuse with the field labels.)
667
677
 
668
- Omits list labels. (note that in the form the labels are rendered again anyway)
678
+ (Note that on a per model basis, you can also globally omit the label or set a unique label value using
679
+ `@@table_label_singular` and `@@table_label_plural` on your model objects.)
680
+
681
+ Note that list labels may be automatically omitted on downnested scaffolds.
682
+
683
+ ### `--no-list-heading`
684
+
685
+ Omits the heading of column names that appears above the 1st row of data.
669
686
 
670
687
  ### `--no-create`
671
688
 
672
- Omits create action.
689
+ Omits new & create actions.
673
690
 
674
691
  ### `--no-delete`
675
692
 
676
- Omits delete action.
693
+ Omits delete button & destroy action.
677
694
 
678
695
  ### `--big-edit`
679
696
 
680
- If you do not want inline editing of your list items but instead to fall back to full page style behavior for your edit views, use `--big-edit`. Turbo still handles the page interactions, but the user is taken to a full-screen edit page instead of an edit-in-place interaction.
697
+ If you do not want inline editing of your list items but instead want to fall back to full page style behavior for your edit views, use `--big-edit`. Turbo still handles the page interactions, but the user is taken to a full-screen edit page instead of an edit-in-place interaction.
681
698
 
682
- ### `--display-list-after-update` (default: false)
699
+ ### `--display-list-after-update`
683
700
 
684
701
  After an update-in-place normally only the edit view is swapped out for the show view of the record you just edited.
685
702
 
686
703
  Sometimes you might want to redisplay the entire list after you make an update (for example, if your action removes that record from the result set).
687
704
 
688
- To do this, use flag `--display_list_after_update`. The update will behave like delete and re-fetch all the records in the result and tell Turbo to swap out the entire list.
705
+ To do this, use flag `--display-list-after-update`. The update will behave like delete and re-fetch all the records in the result and tell Turbo to swap out the entire list.
689
706
 
690
707
 
691
708
 
@@ -695,12 +712,25 @@ To do this, use flag `--display_list_after_update`. The update will behave like
695
712
 
696
713
  HotGlue will copy a file named base_controller.rb to the same folder where it tries to create any controller, unless such a file exists there already.
697
714
 
698
- Obviously, the created controller will always have this base controller as its subclass. In this way, you are encouraged to implement functionality common to the *namespace* (shared between the controllers in the namespace), using this technique.
715
+ The created controller will always have this base controller as its subclass. You are encouraged to implement functionality common to the *namespace* (shared between the controllers in the namespace) using this technique.
716
+
717
+ ## Special Table Labels
718
+
719
+ If your object is very wordy (like MyGreatHook) and you want it to display in the UI as something shorter,
720
+ add `@@table_label_plural = "Hooks"` and `@@table_label_singular = "Hook"`.
721
+
722
+ Hot Glue will use this as the **list heading** and **New record label**, respectively. This affects only the UI only.
723
+
724
+ You can also set these to `nil` to omit the labels completely.
725
+
726
+ Child portals have the headings omitted automatically (there is a heading identifying them already on the parent view where they get included), or you can use the `--no-list-heading` on any specific build.
727
+
699
728
 
700
729
  ## Field Types Supported
701
730
 
702
731
  - Integers that don't end with `_id`: displayed as input fields with type="number"
703
- - Integers that do end with `_id` will be treated automatically as associations. You should have a Rails association defined. (Hot Glue will warn you if it can't find one.)
732
+ - Foreign keys: Integers that do end with `_id` will be treated automatically as associations. You should have a Rails association defined. (Hot Glue will warn you if it can't find one.)
733
+ - Note: if your foreign key has a nonusual class name, it should be using the `class_name:` in the model definition
704
734
  - String: displayed as small input box
705
735
  - Text: displayed as large textarea
706
736
  - Float: displayed as input box
@@ -709,32 +739,57 @@ Obviously, the created controller will always have this base controller as its s
709
739
  - Time: displayed as HTML5 time picker
710
740
  - Boolean: displayed radio buttons yes/ no
711
741
  - Enum - displayed as a drop-down list (defined the enum values on your model). For Rails 6 see https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
742
+ - AFAIK, you must specify the enum definition both in your model and also in your database migration for both Rails 6 + Rails 7
712
743
 
713
744
 
714
745
  # VERSION HISTORY
715
746
 
747
+ #### 2022-02-14 - v0.4.9
748
+ • Fixed issue building models with namespaced class names (e.g. `Fruits::Apple` and `Fruits::Bannana`).
749
+ You can now build against these kinds of models natively (be sure to pass the full model name, with double-colon syntax).
750
+
751
+ • Also fixes issues when associations themselves were namespaced models.
716
752
 
753
+ • The N+1 Killer (!!!)
754
+ - N+1 queries for _any association_ built by the list are now automagically killed by the list controllers.
755
+ - Thanks to the work done back in Rails 5.2, Rails smartly uses either two queries to glob up the data OR one query with a LEFT OUTER JOIN if that's faster. You don't have to think about it. **Thanks Rails 5.2!**
756
+ - Hot Glue now adds `.includes(...)` if it is including an association when it loads the list view to eliminate the N+1s
757
+ - Bullet is still the best way to identify, find, & fix your N+1 queries is still highly recommended. https://github.com/flyerhzm/bullet
758
+
759
+ • Downnest children (portals) can now be created with more space (made wider) by adding one or more `+` to the end of the downnest name, denoting add 1 bootstrap column.
760
+ - e.g. `--downnest=abc+,xyz`
761
+
762
+ The "Abc" portal will take up 5 bootstrap columns and the Xyz portal will take up 4 columns. (++ to indicate 6, `+++` for 7, etc)
763
+
764
+ • Now that you can expand the downnest child portal width, you can easily give them too much width taking up more than 12 bootstrap columns.
765
+ The builder stops you from building if you have taken up too many bootstrap columns, are in _either_ **Smart Layout mode** or **Specified Grouping mode**.
766
+ However, this check is not in place if you are in neither mode, in which case you should watch out for building more than 12 bootstrap columns.
767
+
768
+ • To give a special label to a model, add `@@table_label_plural = "The Things"` and `@@table_label_singular = "The Thing"`.
769
+ This model will now have a list heading of "The Things" instead of its usual name.
770
+ For 'create buttons' and the 'New' screen, the builder will use the singular setting.
771
+ This affects all builds against that model and affects the UI (display) only.
772
+ All route names, table names, and variables are unaffected by this.
773
+
774
+ • You can also use `@@table_label_plural = nil` to set these tables to **omit** the label headings, or use the new flag...
775
+
776
+ • `--no-list-heading` (defaults to false but note several conditions when list headings are now hidden)
777
+
778
+ Omits the list heading. Note that the listing heading is omitted:
779
+ 1) if there is no list,
780
+ 2) if you set the `--no-list-heading` flag,
781
+ 3) if the model has `@@table_label_plural = nil`, or
782
+ 4) if you are constructing a nested child portal with only non-optionalized parents.
783
+
784
+
785
+
786
+ #### 2022-02-09 - v0.4.8.1 - Issue with Installer for v0.4.8
787
+ - There was an issue for the installer for v0.4.8. This new version v0.4.8.1 correts it.
717
788
 
718
789
 
719
790
  #### 2022-02-07 - v0.4.8 Optionalized Nested Parents
720
791
  - optionalized nested parents. to use add `~` in front of any nested parameter you want to make optional
721
792
 
722
- - This is an advanced feature is to use two duplicitous routes to the same controller. You can only use this feature with Gd controller. To use, specify your controller *twice* in your routes.rb. Then, in your `--nest` setting, add `~` to any nested parent you want to **make optional**. "Make optional" means the controller will behave as-if it exists in two places: once, at the normal nest level. Then the same controller will 'exist' again one-level up in your routes. **If the route has sub-routes, you'll need to re-specify the entire subtree also**.
723
- ```
724
- namespace :admin
725
- resources :users do
726
- resources :invoices
727
- end
728
- resoures :invoices
729
- end
730
- ```
731
- We will build the scaffolding once for users and once again for invoice. Even though we have two routes pointed to invoices,
732
- ```
733
- rails generate hot_glue:scaffold User --namespace=admin --gd --downnest=invoices
734
- rails generate hot_glue:scaffold Invoice --namespace=admin --gd --nest=~users
735
- ```
736
- - Notice for the Invoice build, the parent user is *optionalized* (not 'optional'-- optionalized: to be made so it can be made optional). The Invoices controller, which is a Gd controller, will load the User if a user is specified in the route (`/admin/users/:user_id/invoices/`). It will ALSO work at `/admin/invoices` and will switch back into loading directly from the base class when routed this way.
737
- - fixes to specified grouping mode-- the columns you specify now grab up the remaining bootstrap columns to fill space
738
793
 
739
794
  #### 2022-01-26 - v0.4.7 `--nest` has been renamed to `--nested`; please use `--nested` moving forward
740
795
  - `--alt-controller-name` feature from the last release has been removed, I have something better coming soon
@@ -851,8 +906,8 @@ COVERGE=on rake spec
851
906
  --
852
907
  --
853
908
 
854
- Test coverage as of 2022-02-06
855
-
856
- ![Screen Shot 2022-02-06 at 10 26 36 PM](https://user-images.githubusercontent.com/59002/152719855-fdd3da6d-8348-44b9-8753-b0e73eee8065.png)
909
+ Test coverage as of 2022-02-14 (v0.4.9)
910
+
911
+ ![Screen Shot 2022-02-14 at 8 33 29 PM](https://user-images.githubusercontent.com/59002/153975911-30fa9c84-c8d8-49e7-bd5c-e2b958d6f10e.png)
857
912
 
858
913
 
@@ -38,7 +38,7 @@ module HotGlue
38
38
  require 'open-uri'
39
39
 
40
40
  # ask HeliosDev.shop if this email is good
41
- stream = URI.open("https://heliosdev.shop/check_licenses/hot-glue-license?email=#{license_email}")
41
+ stream = URI.open("https://heliosdev.shop/check_licenses/hot-glue?email=#{license_email}")
42
42
  resp = JSON.parse(stream.read)
43
43
 
44
44
  if resp['status'] == 'success'
@@ -4,13 +4,13 @@ module HotGlue
4
4
  module Layout
5
5
  class Builder
6
6
  attr_reader :include_setting,
7
- :downnest_children,
7
+ :downnest_object,
8
8
  :buttons_width, :columns,
9
9
  :smart_layout, :specified_grouping_mode
10
10
 
11
11
  def initialize(params)
12
12
  @include_setting = params[:include_setting]
13
- @downnest_children = params[:downnest_children]
13
+ @downnest_object = params[:downnest_object]
14
14
 
15
15
  @buttons_width = params[:buttons_width]
16
16
 
@@ -32,23 +32,28 @@ module HotGlue
32
32
  buttons: { size: @buttons_width}
33
33
  }
34
34
 
35
- downnest_children.each do |child|
36
- layout_object[:portals][child] = {size: 4}
37
- end
35
+ # downnest_object.each do |child, size|
36
+ # layout_object[:portals][child] = {size: size}
37
+ # end
38
38
 
39
39
  # smart layout: 2 columns per field; 4 column for EACH downnested portals, 2 column for buttons
40
- how_many_downnest = downnest_children.size
40
+ how_many_downnest = downnest_object.size
41
+
42
+ bootstrap_columns = (12 - @buttons_width )
43
+
44
+ bootstrap_columns = bootstrap_columns - (downnest_object.collect{|k,v| v}.sum)
41
45
 
42
- bootstrap_columns = (12-@buttons_width )
43
- bootstrap_columns = bootstrap_columns - (how_many_downnest*4)
44
46
  available_columns = (bootstrap_columns / 2).floor # bascially turns the 12-column grid into a 6-column grid
45
47
 
46
48
  if available_columns < 0
47
49
  raise "Cannot build layout with #{how_many_downnest} downnested portals"
48
50
  end
49
51
 
50
- @downnest_children_width = []
51
- @downnest_children.each_with_index{ |child, i| @downnest_children_width[i] = 4}
52
+ downnest_children_width = []
53
+
54
+ downnest_object.each do |child, size|
55
+ layout_object[:portals][child] = {size: size}
56
+ end
52
57
 
53
58
 
54
59
  if smart_layout
@@ -56,6 +61,10 @@ module HotGlue
56
61
  #
57
62
 
58
63
  if columns.size > available_columns
64
+ if available_columns == 0
65
+ raise "Oopps... No available columns in SMART LAYOUT"
66
+ end
67
+
59
68
  each_col_can_have = (columns.size.to_f / available_columns.to_f).round
60
69
 
61
70
  layout_object[:columns][:container] = (0..available_columns-1).collect { |x|
@@ -94,9 +94,9 @@ module HotGlue
94
94
  end
95
95
 
96
96
  is_owner = col == ownership_field
97
- display_column = HotGlue.derrive_reference_name(assoc.class_name)
97
+ assoc_class_name = assoc.active_record.name
98
+ display_column = HotGlue.derrive_reference_name(assoc_class_name)
98
99
 
99
- # TODO: add is_owner && check if this nested arg is optional
100
100
  (is_owner ? "<% unless @#{assoc_name} %>\n" : "") +
101
101
  " <%= f.collection_select(:#{col}, #{assoc.class_name}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col} }, class: 'form-control') %>\n" +
102
102
  (is_owner ? "<% else %>\n <%= @#{assoc_name}.#{display_column} %>" : "") +
@@ -209,9 +209,8 @@ module HotGlue
209
209
  exit
210
210
  # raise(HotGlue::Error,exit_message)
211
211
  end
212
-
213
- display_column = HotGlue.derrive_reference_name(assoc.class_name)
214
-
212
+ assoc_class_name = assoc.active_record.name
213
+ display_column = HotGlue.derrive_reference_name(assoc_class_name)
215
214
  "<%= #{singular}.#{assoc.name.to_s}.try(:#{display_column}) || '<span class=\"content alert-danger\">MISSING</span>'.html_safe %>"
216
215
 
217
216
  else
@@ -12,6 +12,15 @@ module HotGlue
12
12
  class Error < StandardError
13
13
  end
14
14
 
15
+ def self.construct_downnest_object(input)
16
+ res = input.split(",").map { |child|
17
+ child_name = child.gsub("+","")
18
+ extra_size = child.count("+")
19
+ {child_name => 4+extra_size}
20
+ }
21
+ Hash[*res.collect{|hash| hash.collect{|key,value| [key,value].flatten}.flatten}.flatten]
22
+ end
23
+
15
24
  def self.optionalized_ternary(params)
16
25
  namespace = params[:namespace] || nil
17
26
  target = params[:target]
@@ -116,7 +125,9 @@ module HotGlue
116
125
  class_option :smart_layout, type: :boolean, default: false
117
126
  class_option :markup, type: :string, default: nil # deprecated -- use in app config instead
118
127
  class_option :layout, type: :string, default: nil # if used here it will override what is in the config
119
- class_option :no_list_labels, type: :boolean, default: false
128
+ class_option :no_list_label, type: :boolean, default: false
129
+ class_option :no_list_heading, type: :boolean, default: false
130
+
120
131
  class_option :before_list_labels, type: :boolean, default: false
121
132
 
122
133
  def initialize(*meta_args)
@@ -191,6 +202,12 @@ module HotGlue
191
202
 
192
203
 
193
204
  @singular = args.first.tableize.singularize # should be in form hello_world
205
+
206
+
207
+ if @singular.include?("/")
208
+ @singular = @singular.split("/").last
209
+ end
210
+
194
211
  @plural = options['plural'] || @singular + "s" # supply to override; leave blank to use default
195
212
  @namespace = options['namespace'] || nil
196
213
 
@@ -217,9 +234,10 @@ module HotGlue
217
234
 
218
235
  @nested = (!options['nested'].empty? && options['nested']) || nil
219
236
 
220
- @singular_class = @singular.titleize.gsub(" ", "")
221
- @exclude_fields = []
237
+ @singular_class = args.first # note this is the full class name with a model namespace
222
238
 
239
+
240
+ @exclude_fields = []
223
241
  @exclude_fields += options['exclude'].split(",").collect(&:to_sym)
224
242
 
225
243
  if !options['include'].empty?
@@ -246,7 +264,9 @@ module HotGlue
246
264
 
247
265
  @no_edit = options['no_edit'] || false
248
266
  @no_list = options['no_list'] || false
249
- @no_list_labels = options['no_list_labels'] || false
267
+ @no_list_label = options['no_list_label'] || false
268
+ @no_list_heading = options['no_list_heading'] || false
269
+
250
270
  @display_list_after_update = options['display_list_after_update'] || false
251
271
  @smart_layout = options['smart_layout']
252
272
 
@@ -258,13 +278,13 @@ module HotGlue
258
278
  @container_name = @layout == "hotglue" ? "scaffold-container" : "container-fluid"
259
279
  @downnest = options['downnest'] || false
260
280
 
261
- @downnest_children = []
262
-
281
+ @downnest_children = [] # TODO: defactor @downnest_children in favor of downnest_object
282
+ @downnest_object = {}
263
283
  if @downnest
264
- @downnest_children = @downnest.split(",")
284
+ @downnest_children = @downnest.split(",").map{|child| child.gsub("+","")}
285
+ @downnest_object = HotGlue.construct_downnest_object(@downnest)
265
286
  end
266
287
 
267
-
268
288
  if @god
269
289
  @auth = nil
270
290
  end
@@ -364,7 +384,7 @@ module HotGlue
364
384
 
365
385
  builder = HotGlue::Layout::Builder.new({
366
386
  include_setting: options['include'],
367
- downnest_children: @downnest_children,
387
+ downnest_object: @downnest_object,
368
388
  buttons_width: buttons_width,
369
389
  columns: @columns,
370
390
  smart_layout: @smart_layout
@@ -372,6 +392,7 @@ module HotGlue
372
392
  @layout_object = builder.construct
373
393
 
374
394
  @menu_file_exists = true if @nested_args.none? && File.exists?("#{Rails.root}/app/views/#{namespace_with_trailing_dash}_menu.#{@markup}")
395
+
375
396
  end
376
397
 
377
398
  def identify_object_owner
@@ -379,6 +400,7 @@ module HotGlue
379
400
 
380
401
  if !@object_owner_sym.empty?
381
402
  auth_assoc_field = auth_assoc + "_id" unless @god
403
+
382
404
  assoc = eval("#{singular_class}.reflect_on_association(:#{@object_owner_sym})")
383
405
 
384
406
  if assoc
@@ -422,6 +444,7 @@ module HotGlue
422
444
  @columns = @the_object.columns.map(&:name).map(&:to_sym).reject{|field| !@include_fields.include?(field) }
423
445
  end
424
446
 
447
+ @associations = []
425
448
  @columns.each do |col|
426
449
  if col.to_s.starts_with?("_")
427
450
  @show_only << col
@@ -431,11 +454,10 @@ module HotGlue
431
454
  if col.to_s.ends_with?("_id")
432
455
  # guess the association name label
433
456
  assoc_name = col.to_s.gsub("_id","")
434
- assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
435
457
 
436
458
 
437
459
  begin
438
- eval(assoc.class_name)
460
+ assoc_model = eval("#{singular_class}.reflect_on_association(:#{assoc_name}).active_record")
439
461
  rescue NameError => e
440
462
  exit_message = "*** Oops: The model #{singular_class} is missing an association for :#{assoc_name} or the model #{assoc_name.titlecase} doesn't exist. TODO: Please implement a model for #{assoc_name.titlecase}; your model #{singular_class.titlecase} should belong_to :#{assoc_name}. To make a controller that can read all records, specify with --god."
441
463
  puts exit_message
@@ -443,20 +465,21 @@ module HotGlue
443
465
  end
444
466
 
445
467
 
446
- if assoc.nil?
468
+ if assoc_model.nil?
447
469
  exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
448
470
  puts exit_message
449
471
  raise(HotGlue::Error,exit_message)
450
472
  end
451
473
 
452
- assoc_class = eval(assoc.class_name)
474
+ @associations << assoc_name.to_sym
475
+ assoc_class = eval(assoc_model.name)
453
476
  name_list = [:name, :to_label, :full_name, :display_name, :email]
454
477
  if name_list.collect{ |field|
455
478
  assoc_class.column_names.include?(field.to_s) || assoc_class.instance_methods.include?(field)
456
479
  }.any?
457
480
  # do nothing here
458
481
  else
459
- exit_message = "*** Oops: Missing a label for #{assoc.class_name.upcase}. Can't find any column to use as the display label for the #{assoc.name.to_s} association on the #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, or 5) email directly on your #{assoc.class_name.upcase} model (either as database field or model methods), then RERUN THIS GENERATOR. (If more than one is implemented, the field to use will be chosen based on the rank here, e.g., if name is present it will be used; if not, I will look for a to_label, etc)"
482
+ exit_message = "\n*** Oops: Missing a label for `#{assoc_class}`. Can't find any column to use as the display label for the #{assoc_name} association on the #{singular_class} model. TODO: Please implement just one of: \n1) name, \n2) to_label, \n3) full_name, \n4) display_name \n5) email \nYou can implement any of these directly on your`#{assoc_class}` model (can be database fields or model methods) or alias them to field you want to use as your display label. Then RERUN THIS GENERATOR. (Field used will be chosen based on rank here.)"
460
483
  raise(HotGlue::Error,exit_message)
461
484
  end
462
485
  end
@@ -512,16 +535,12 @@ module HotGlue
512
535
  end
513
536
 
514
537
  def list_column_headings
515
- if @nested_args.any?
538
+ if @layout == "bootstrap"
539
+ column_width = @layout_object[:columns][:size_each]
540
+ col_identifier = "col-md-#{column_width}"
541
+ elsif @layout == "hotglue"
516
542
  column_width = each_col * @columns.count
517
- else
518
- column_width = 0
519
- end
520
-
521
- if !@smart_layout
522
- col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col-md-1"
523
- else
524
- col_identifier = @layout == "hotglue" ? "scaffold-cell" : "col-md-2"
543
+ col_identifier = "scaffold-cell"
525
544
  end
526
545
 
527
546
  @template_builder.list_column_headings(
@@ -586,6 +605,10 @@ module HotGlue
586
605
  @singular
587
606
  end
588
607
 
608
+ def singular_class_name
609
+ @singular_class
610
+ end
611
+
589
612
  def plural_name
590
613
  plural
591
614
  end
@@ -900,6 +923,22 @@ module HotGlue
900
923
  @each_col ||= each_col
901
924
  end
902
925
 
926
+ def list_label
927
+ if(eval("#{class_name}.class_variable_defined?(:@@table_label_plural)"))
928
+ eval("#{class_name}.class_variable_get(:@@table_label_plural)")
929
+ else
930
+ plural.gsub("_", " ").upcase
931
+ end
932
+ end
933
+
934
+ def thing_label
935
+ if(eval("#{class_name}.class_variable_defined?(:@@table_label_singular)"))
936
+ eval("#{class_name}.class_variable_get(:@@table_label_singular)")
937
+ else
938
+ singular.gsub("_", " ").upcase
939
+ end
940
+ end
941
+
903
942
  def each_col
904
943
  return col_width if @columns.count == 0
905
944
  (col_width/(@columns.count)).to_i
@@ -1030,6 +1069,15 @@ module HotGlue
1030
1069
  end
1031
1070
  end
1032
1071
 
1072
+
1073
+ def n_plus_one_includes
1074
+ if @associations.any?
1075
+ ".includes(" + @associations.map{|x| ":#{x.to_s}"}.join(", ") + ")"
1076
+ else
1077
+ ""
1078
+ end
1079
+ end
1080
+
1033
1081
  def nested_for_turbo_nested_constructor(top_level = true)
1034
1082
  instance_symbol = "@" if top_level
1035
1083
  instance_symbol = "" if !top_level
@@ -1052,7 +1100,6 @@ module HotGlue
1052
1100
  end
1053
1101
  end
1054
1102
 
1055
-
1056
1103
  private # thor does something fancy like sending the class all of its own methods during some strange run sequence
1057
1104
  # does not like public methods
1058
1105
  def cc_filename_with_extensions(name, file_format = format)
@@ -40,24 +40,29 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
40
40
  @<%= @nested_set[0][:singular] %> ||= <%= root_object %> <% else %>
41
41
  @<%= @nested_set[0][:singular] %> ||= <%= root_object %>.find(params[:<%= @nested_set[0][:singular] %>_id])<%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set[0][:optional] %> <% end %>
42
42
  end
43
- <% end %><% if any_nested? %><% nest_chain = [@nested_set[0][:singular]]; this_scope = @nested_set[0][:plural]; %> <% @nested_set[1..-1].each_with_index { |arg,index|
44
- this_scope = "#{nest_chain.last}.#{arg[:plural]}"
45
- nest_chain << arg %>
43
+ <% end %><% if any_nested? %><% nest_chain = [@nested_set[0][:singular]]; this_scope = @nested_set[0][:plural]; %>
44
+ <% for index in 0..(@nested_set.count - 1) do
45
+ arg = @nested_set[index]
46
+ last_arg = (index == 0 ? nil : @nested_set[index-1])
47
+
48
+ this_scope = "#{nest_chain.last}.#{arg[:plural]}"
49
+ nest_chain << arg %>
46
50
  def <%= arg[:singular] %>
47
- @<%= arg[:singular] %> ||= (<%= this_scope %>.find(params[:<%= arg[:singular] %>_id])<%= " if params.include?(:#{@nested_set[index][:singular]}_id)" if @god && arg[:optional] %>)<% if @god && arg[:optional] %> || (<%= collect_objects[index] %>.find(params[:<%= arg[:singular] %>_id]) if params.include?(:<%= arg[:singular] %>_id) ) <% end %>
48
- end<% } %> <% end %> <% if !@self_auth %>
51
+ @<%= arg[:singular] %> ||= (<%= this_scope %>.find(params[:<%= arg[:singular] %>_id])<%= " if params.include?(:#{last_arg[:singular]}_id)" if last_arg && @god && last_arg[:optional] %>)
52
+ <% if @god && (last_arg[:optional] ) %>@<%= arg[:singular] %> ||= (<%= collect_objects[index-1] %>.find(params[:<%= arg[:singular] %>_id]) if params.include?(:<%= arg[:singular] %>_id) ) <% end %>
53
+ end<% end %> <% end %> <% if !@self_auth %>
49
54
 
50
55
  def load_<%= singular_name %>
51
56
  @<%= singular_name %> = (<%= object_scope.gsub("@",'') %>.find(params[:id])<%= " if params.include?(:#{@nested_set.last[:singular]}_id)" if @nested_set[0] && @nested_set[0][:optional] %>)<% if @nested_set[0] && @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %>
52
57
  end
53
58
  <% else %>
54
59
  def load_<%= singular_name %>
55
- @<%= singular_name %> = (<%= auth_object.gsub("@",'') %><%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set[0][:optional] %>)<% if @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %>
60
+ @<%= singular_name %> = (<%= auth_object.gsub("@",'') %><%= " if params.include?(:#{@nested_set[0][:singular]}_id)" if @nested_set.any? && @nested_set[0][:optional] %>)<% if @nested_set.any? && @nested_set[0][:optional] %> || <%= class_name %>.find(params[:id])<% end %>
56
61
  end<% end %>
57
62
 
58
63
  def load_all_<%= plural %> <% if !@self_auth %>
59
- @<%= plural_name %> = ( <%= object_scope.gsub("@",'') %>.page(params[:page])<%= " if params.include?(:#{ @nested_set.last[:singular]}_id)" if @nested_set[0] && @nested_set[0][:optional] %>) <% if @nested_set[0] && @nested_set[0][:optional] %> || <%= class_name %>.all<% end %> <% else %>
60
- @<%= plural_name %> = <%= class_name %>.where(id: <%= auth_object.gsub("@",'') %>.id) # returns iterable even though this <%= singular_name %> is anly allowed access to themselves<% end %>
64
+ @<%= plural_name %> = ( <%= object_scope.gsub("@",'') %>.page(params[:page])<%= n_plus_one_includes %><%= " if params.include?(:#{ @nested_set.last[:singular]}_id)" if @nested_set.any? && @nested_set[0] && @nested_set[0][:optional] %>) <% if @nested_set[0] && @nested_set[0][:optional] %> || <%= class_name %>.all<% end %> <% else %>
65
+ @<%= plural_name %> = <%= class_name %>.where(id: <%= auth_object.gsub("@",'') %>.id)<%= n_plus_one_includes %> # returns iterable even though this <%= singular_name %> is only allowed access to themselves<% end %>
61
66
  end
62
67
 
63
68
  def index
@@ -1,24 +1,28 @@
1
1
  <\%= turbo_frame_tag "<%= plural %>-list" <%= nested_for_turbo_id_list_constructor %> do %>
2
2
  <div class="<%= @container_name %> scaffold-list">
3
- <% unless @no_list || @nested_args.any? %><h4><%= plural.gsub("_", " ").upcase %></h4><% end %>
3
+ <% unless @no_list || @no_list_label || (@nested_set.any? && !@nested_set.collect{|x| x[:optional]}.any?) %>
4
+ <% unless list_label.nil? %><h4>
5
+ <%= list_label %>
6
+ </h4><% end %>
7
+ <% end %>
4
8
 
5
9
  <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %><br /><% end %>
6
10
 
7
11
  <% unless @no_list %>
8
- <% unless @no_list_labels %>
12
+ <% unless @no_list_heading %>
9
13
  <div class="row scaffold-heading-row">
10
14
  <%= list_column_headings %>
11
- <% if @downnest_children.any? %>
12
- <% each_downnest_width = @downnest_children.count == 1 ? 40 : (60/@downnest_children.count).floor %>
15
+ <% if @downnest_object.any? %>
16
+ <%# each_downnest_width = @downnest_object.count == 1 ? 40 : (60/@downnest_object.count).floor %>
13
17
  <% downnest_column_style = @layout == "hotglue" ? 'style="flex-basis: ' + each_downnest_width.to_s + '%;' : "" %>
14
18
 
15
- <% @downnest_children.each_with_index do |downnest,i| %>
16
- <div class=" scaffold-col-heading<%= " col-sm-#{ @layout_object[:portals][downnest][:size] }" if @layout=="bootstrap" %>" <%= downnest_column_style %>>
17
- <strong>
18
- <%= downnest.titleize %>
19
- </strong>
20
- </div>
21
- <% end %>
19
+ <% @downnest_object.each do |downnest,i| %>
20
+ <div class=" scaffold-col-heading<%= " col-sm-#{ @layout_object[:portals][downnest][:size] }" if @layout=="bootstrap" %>" <%= downnest_column_style %>>
21
+ <strong>
22
+ <%= downnest.titleize %>
23
+ </strong>
24
+ </div>
25
+ <% end %>
22
26
  <% end %>
23
27
 
24
28
  <% button_column_style = @layout == "hotglue" ? 'style="flex-basis: 150px' : "" %>
@@ -1,5 +1,5 @@
1
1
  <\%= turbo_frame_tag "<%= singular %>-new" do %>
2
2
  <div>
3
- <\%= link_to "New <%= singular.titlecase %>", <%= new_path_name %>, disable_with: "Loading...", class: "new-<%= singular %>-button btn btn-primary pull-right <%= 'btn-sm' if @nested_args.any? %> " %>
3
+ <\%= link_to "New <%= thing_label %>", <%= new_path_name %>, disable_with: "Loading...", class: "new-<%= singular %>-button btn btn-primary pull-right <%= 'btn-sm' if @nested_args.any? %> " %>
4
4
  </div>
5
5
  <\% end %>
@@ -1,6 +1,6 @@
1
1
  <\%= turbo_frame_tag "<%= singular %>-new" do %>
2
2
  <h3>
3
- New <%= singular.titlecase %>
3
+ New <%= thing_label %>
4
4
  </h3>
5
5
  <\%= form_with model: <%= singular %>, url: <%= form_path_new_helper %>, method: :post do |f| \%>
6
6
  <\%= render partial: "<%= namespace_with_slash + @controller_build_folder %>/form",
@@ -3,7 +3,7 @@
3
3
  <% if @downnest_children.any? %>
4
4
  <% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
5
5
 
6
- <% @downnest_children.each_with_index do |downnest,i| %>
6
+ <% @downnest_object.each do |downnest, size| %>
7
7
 
8
8
  <% downnest_object = eval("#{singular_class}.reflect_on_association(:#{downnest})") %>
9
9
  <% if downnest_object.nil?; raise "no relationship for downnested portal `#{downnest}` found on `#{singular_class}`; please check relationship for has_many :#{downnest}"; end; %>
@@ -9,7 +9,7 @@
9
9
  <\% end %>
10
10
 
11
11
  <h2>Editing <\%= @<%= @singular %>.<%= display_class %> %></h2>
12
- <\%= form_with model: <%= "@" + singular%>, url: <%= form_path_edit_helper %> do |f| %>
12
+ <\%= form_with model: <%= "@" + singular %>, url: <%= form_path_edit_helper %> do |f| %>
13
13
  <\%= render partial: "form", locals: {:<%= singular %> => <%= "@" + singular%>, f: f}<%= @nested_set.collect{|arg| ".merge(@#{arg[:singular]} ? {#{arg[:singular]}: @#{arg[:singular]}} : {})" }.join %> \%>
14
14
  <\% end %>
15
15
 
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.4.8.1'
3
+ CURRENT = '0.4.9.2'
4
4
  end
5
5
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot-glue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.8.1
4
+ version: 0.4.9.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jason Fleetwood-Boldt
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-02-09 00:00:00.000000000 Z
11
+ date: 2022-02-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -125,7 +125,7 @@ files:
125
125
  - lib/hot-glue.rb
126
126
  - lib/hotglue/engine.rb
127
127
  - lib/hotglue/version.rb
128
- homepage: https://jfbcodes.com/p/hot-glue-in-depth-tutorial?utm_source=rubygems.org&utm_campaign=rubygems_link
128
+ homepage: https://heliosdev.shop/p/hot-glue?utm_source=rubygems.org&utm_campaign=rubygems_link
129
129
  licenses:
130
130
  - Commercial with free option
131
131
  metadata: