hot-glue 0.5.6 → 0.5.8
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.github/FUNDING.yml +1 -1
- data/LICENSE +12 -5
- data/README.md +302 -47
- data/lib/generators/hot_glue/install_generator.rb +2 -2
- data/lib/generators/hot_glue/layout/builder.rb +6 -2
- data/lib/generators/hot_glue/layout_strategy/base.rb +1 -0
- data/lib/generators/hot_glue/layout_strategy/bootstrap.rb +17 -3
- data/lib/generators/hot_glue/markup_templates/erb.rb +96 -41
- data/lib/generators/hot_glue/scaffold_generator.rb +165 -53
- data/lib/generators/hot_glue/templates/controller.rb.erb +42 -30
- data/lib/generators/hot_glue/templates/erb/_form.erb +2 -2
- data/lib/generators/hot_glue/templates/erb/_line.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/_new_button.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/_new_form.erb +4 -4
- data/lib/generators/hot_glue/templates/erb/_show.erb +2 -2
- data/lib/generators/hot_glue/templates/erb/update.turbo_stream.erb +1 -1
- data/lib/generators/hot_glue/templates/haml/_form.haml +1 -1
- data/lib/generators/hot_glue/templates/system_spec.rb.erb +56 -34
- data/lib/hotglue/version.rb +1 -1
- data/script/clean_generated_code +5 -0
- data/script/test +10 -2
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 14d86dc6800770982fbc2775311698b33f0e21180a3f3e8e6b0d8078dc304629
|
4
|
+
data.tar.gz: 8682fffd425887c274e016b382c374f95fde00fc7607ada565d590139adabc9d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f142e3f8e048193ae628d446826dc9628ac37db747f25dbee38259f9ec7aee41b6ee91ded483065a28e80d777468b949e72b7021146a6812ee6e8ae58b0034bf
|
7
|
+
data.tar.gz: cfe2f196c675d6d89105e153b79f8712cb5a9543a64900eac06976705e7bb39dff688db6b0db93e9bc2871be852101790856b5ad526088ff344fed0c9b8c854c
|
data/.github/FUNDING.yml
CHANGED
@@ -1 +1 @@
|
|
1
|
-
custom: ["https://
|
1
|
+
custom: ["https://twitter.com/HotGlueForRails", "https://school.jasonfleetwoodboldt.com/8188?utm_source=github.com&utm_campaign=github_hot_glue_repo_funding_link"]
|
data/LICENSE
CHANGED
@@ -1,10 +1,17 @@
|
|
1
|
-
© 2022 Jason Fleetwood-Boldt. All Rights Reserved
|
2
|
-
This software is 'fauxpen source,' which means you can think of it like 'free' as in speech but not 'free' as in beer....
|
3
1
|
|
4
|
-
|
2
|
+
|
3
|
+
Copyright © 2022 Jason Fleetwood-Boldt. All Rights Reserved
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
6
|
+
|
7
|
+
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
8
|
+
|
9
|
+
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
10
|
+
|
11
|
+
|
5
12
|
|
6
13
|
TO PURCHASE A COMMERCIAL USAGE LICENSE PLEASE VISIT
|
7
14
|
https://heliosdev.shop/hot-glue-license
|
8
15
|
|
9
|
-
OR PURCHASE THE
|
10
|
-
https://
|
16
|
+
OR PURCHASE THE TUTORIALS AT
|
17
|
+
https://school.jasonfleetwoodboldt.com/8188/?utm_source=github.com
|
data/README.md
CHANGED
@@ -11,16 +11,16 @@ Alternatively, you can use this tool to create a Turbo-backed *section* of your
|
|
11
11
|
|
12
12
|
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.
|
13
13
|
|
14
|
-
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.
|
14
|
+
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. (Handily, Hot Glue leaves the command you used in a comment at the top of your generated controller so you can regenerate it again in the future.)
|
15
15
|
|
16
16
|
Hot Glue generates functionality that is quick and dirty. It lets you be crafty. As with a real glue gun, use it with caution.
|
17
17
|
|
18
18
|
* Build plug-and-play scaffolding mixing generated ERB with the power of Hotwire and Turbo-Rails
|
19
19
|
* Everything edits-in-place (unless you use `--big-edit`)
|
20
|
-
* Automatically reads your models (make them
|
20
|
+
* Automatically reads your models (make them, add relationships, **and** migrate your database before building your scaffolding!)
|
21
21
|
* Excellent for CREATE-READ-UPDATE-DELETE (CRUD), lists with pagination
|
22
22
|
* Great for prototyping, but you should learn Rails fundamentals first.
|
23
|
-
* 'Packaged' with Devise, Kaminari, Rspec, FontAwesome
|
23
|
+
* 'Packaged' with Devise, Kaminari, Rspec, FontAwesome (optional)
|
24
24
|
* Create system specs automatically along with the generated code.
|
25
25
|
* Nest your routes model-by-model for built-in poor man's authentication.
|
26
26
|
* Throw the scaffolding away when your app is ready to graduate to its next phase.
|
@@ -29,19 +29,19 @@ How is it different than Rails scaffolding?
|
|
29
29
|
|
30
30
|
Although inspired by the Rails scaffold generators (built-in to Rails), Hot Glue does something similiar but has made opinionated decisions that deviate from the normal Rails scaffold:
|
31
31
|
|
32
|
-
1. The Hot Glue scaffolds are complete packages and pre-optimized for 'edit-in-place.' (the Rails
|
32
|
+
1. The Hot Glue scaffolds are complete packages and pre-optimized for 'edit-in-place.' (the Rails scaffolding still generates views that make you flip between pages to do create/update operations)
|
33
33
|
2. Hot Glue does not create your models along with your scaffolding. Instead, create them first using `rails generate model X`
|
34
|
-
3. Hot Glue *reads* the fields on your database *and* the relationships defined on your models. Unlike the Rails scaffolding you must add relationships and
|
34
|
+
3. Hot Glue *reads* the fields on your database *and* the relationships defined on your models. Unlike the Rails scaffolding you must add relationships and migrate your DB before building your scaffolding.
|
35
35
|
4. Hot Glue has many more features for building layouts quickly, like choosing which fields to include or exclude and how to lay them out on the page, for stitching together related objects (nesting and child portals), and more.
|
36
36
|
|
37
|
-
Other than the opinionated differences and additional features, Hot Glue produces code that is fundamentally very similiar and works consistent with the Rails 7
|
37
|
+
Other than the opinionated differences and additional features, Hot Glue produces code that is fundamentally very similiar and works consistent with the Rails 7 Hotwire & Turbo paradigms.
|
38
38
|
|
39
39
|
# Get Hot Glue
|
40
40
|
|
41
|
-
## [GET THE COURSE TODAY](https://
|
41
|
+
## [GET THE COURSE TODAY](https://school.jasonfleetwoodboldt.com/8188/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) **only $60 USD!**
|
42
42
|
|
43
43
|
|
44
|
-
[![Hot Glue Course](https://user-images.githubusercontent.com/59002/189544503-6edbcd40-1728-4b13-ac9a-c7772ccb8284.jpg)](https://
|
44
|
+
[![Hot Glue Course](https://user-images.githubusercontent.com/59002/189544503-6edbcd40-1728-4b13-ac9a-c7772ccb8284.jpg)](https://school.jasonfleetwoodboldt.com/8188?utm_source=github.com&utm_campaign=github_hot_glue_readme_page)
|
45
45
|
|
46
46
|
---
|
47
47
|
---
|
@@ -366,13 +366,15 @@ Alternatively, you can define your own driver like so:
|
|
366
366
|
|
367
367
|
TitleCase class name of the thing you want to build a scaffoling for.
|
368
368
|
|
369
|
+
```
|
369
370
|
rails generate hot_glue:scaffold Thing
|
371
|
+
```
|
370
372
|
|
371
|
-
(note: Your Thing object must belong_to an authenticated User or alternatively you must create a Gd controller, see below.)
|
373
|
+
(note: Your `Thing` object must `belong_to` an authenticated `User` or alternatively you must create a Gd controller, see below.)
|
372
374
|
|
373
375
|
## Options With Arguments
|
374
376
|
|
375
|
-
All options two dashes (
|
377
|
+
All options begin with two dashes (`--`) and a followed by an `=` and a value
|
376
378
|
|
377
379
|
### `--namespace=`
|
378
380
|
|
@@ -578,7 +580,7 @@ The short form looks like this. It presumes there is a 'pets' association from `
|
|
578
580
|
|
579
581
|
(The long form equivalent of this would be `--hawk=pet_id{current_user.pets}`)
|
580
582
|
|
581
|
-
This is covered in [Example #3 in the Hot Glue Tutorial](https://
|
583
|
+
This is covered in [Example #3 in the Hot Glue Tutorial](https://school.jasonfleetwoodboldt.com/8188)
|
582
584
|
|
583
585
|
To hawk to a scope that is not the currently authenticated user, use the long form with `{...}`
|
584
586
|
to specify the scope. Be sure to note to add the association name itself, like `users`:
|
@@ -588,7 +590,7 @@ to specify the scope. Be sure to note to add the association name itself, like `
|
|
588
590
|
This would hawk the Appointment's `user_id` key to any users who are within the scope of the
|
589
591
|
current_user's has_many association (so, for any other "my" family, would be `current_user.family.users`).
|
590
592
|
|
591
|
-
This is covered in [Example #4 in the Hot Glue Tutorial](https://
|
593
|
+
This is covered in [Example #4 in the Hot Glue Tutorial](https://school.jasonfleetwoodboldt.com/8188)
|
592
594
|
|
593
595
|
|
594
596
|
### `--plural=`
|
@@ -608,10 +610,6 @@ ActiveSupport::Inflector.inflections do |inflect|
|
|
608
610
|
end
|
609
611
|
```
|
610
612
|
|
611
|
-
### `--form-labels-position` (default: `after`; options are **before**, **after**, and **omit**)
|
612
|
-
By default form labels appear after the form inputs. To make them appear before or omit them, use this flag.
|
613
|
-
|
614
|
-
See also `--form-placeholder-labels` to use placeolder labels.
|
615
613
|
|
616
614
|
|
617
615
|
|
@@ -715,11 +713,31 @@ This is what would happen if 9 fields, specified in the order A,B,C,D,E,F,G,H,I,
|
|
715
713
|
### `--show-only=`
|
716
714
|
(separate field names by COMMA)
|
717
715
|
|
718
|
-
Any fields only the 'show-only' list will appear as non-editable on the
|
716
|
+
Any fields only the 'show-only' list will appear as non-editable on the generated form for both new & edit actions. (visible only)
|
719
717
|
|
720
718
|
IMPORTANT: By default, all fields that begin with an underscore (`_`) are automatically show-only.
|
721
719
|
|
722
|
-
|
720
|
+
This is for fields you want globally non-editable by users in your app. For example, a counter cache or other field set only by a backend mechanism.
|
721
|
+
|
722
|
+
|
723
|
+
### `--update-show-only`
|
724
|
+
(separate field names by COMMA)
|
725
|
+
|
726
|
+
Fields on the `update show only` (and not on the `show only` list) will appear as non-editible only for the **edit** action, but will still allow entry for the **create** action.
|
727
|
+
|
728
|
+
Note that Hot Glue still generates a singular partial (`_form`) for both actions, but your form will now contain statements like:
|
729
|
+
|
730
|
+
```
|
731
|
+
<% if action_name == 'edit' %>
|
732
|
+
<%= xyz.name %><
|
733
|
+
<% else %>
|
734
|
+
<%= f.text_field :name %>
|
735
|
+
<% end %>
|
736
|
+
```
|
737
|
+
|
738
|
+
This works for both regular fields, association fields, and alt lookup fields.
|
739
|
+
|
740
|
+
|
723
741
|
|
724
742
|
### `--ujs_syntax=true` (Default is set automatically based on whether you have turbo-rails installed)
|
725
743
|
|
@@ -756,7 +774,7 @@ The bang (`!`) methods can respond in one of four ways:
|
|
756
774
|
|
757
775
|
This means you can be a somewhat lazy about your bang methods, but keep in mind the truth operator compares boolean true NOT any object is truth. So your return object must either be actually true (boolean), or an object that is string or string-like (responds to .to_s). Want to just say it didn’t work? Return false. Want to just say it was OK? Return true. Want to say it was successful but provide a more detailed response? Return a string.
|
758
776
|
|
759
|
-
Finally, you can raise an ActiveRecord error which will also get passed to the user
|
777
|
+
Finally, you can raise an ActiveRecord error which will also get passed to the user in the flash alert area.
|
760
778
|
|
761
779
|
For more information see Example 5 in the Tutorial
|
762
780
|
|
@@ -812,15 +830,106 @@ Omits pagination. (All list views have pagination by default.)
|
|
812
830
|
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.)
|
813
831
|
|
814
832
|
|
815
|
-
### `--no-list-label`
|
816
833
|
|
817
|
-
|
834
|
+
### `--no-create`
|
835
|
+
|
836
|
+
Omits new & create actions.
|
837
|
+
|
838
|
+
### `--no-delete`
|
839
|
+
|
840
|
+
Omits delete button & destroy action.
|
841
|
+
|
842
|
+
### `--big-edit`
|
843
|
+
|
844
|
+
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.
|
845
|
+
|
846
|
+
### `--display-list-after-update`
|
847
|
+
|
848
|
+
After an update-in-place normally only the edit view is swapped out for the show view of the record you just edited.
|
849
|
+
|
850
|
+
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).
|
851
|
+
|
852
|
+
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.
|
853
|
+
|
854
|
+
### `--with-turbo-streams`
|
855
|
+
|
856
|
+
If and only if you specify `--with-turbo-streams`, your views will contain `turbo_stream_from` directives. Whereas your views will always contain `turbo_frame_tags` (wether or not this flag is specified) and will use the Turbo stream replacement mechanism for non-idempotent actions (create & update). This flag just brings the magic of live-reload to the scaffold interfaces themselves.
|
857
|
+
|
858
|
+
**_To test_**: Open the same interface in two separate browser windows. Make an edit in one window and watch your edit appear in the other window instantly.
|
859
|
+
|
860
|
+
This happens using two interconnected mechanisms:
|
861
|
+
|
862
|
+
1) by default, all Hot Glue scaffold is wrapped in `turbo_frame_tag`s. The id of these tags is your namespace + the Rails dom_id(...). That means all Hot Glue scaffold is namespaced to the namespaces you use and won't collide with other turbo_frame_tag you might be using elsewhere
|
863
|
+
|
864
|
+
2) by appending **model callbacks**, we can automatically broadcast updates to the users who are using the Hot Glue scaffold. The model callbacks (after_update_commit and after_destroy_commit) get appended automatically to the top of your model file. Each model callback targets the scaffold being built (so just this scaffold), using its namespace, and renders the line partial (or destroys the content in the case of delete) from the scaffolding.
|
865
|
+
|
866
|
+
please note that *creating* and *deleting* do not yet have a full & complete implementation: Your pages won't re-render the pages being viewed cross-peer (that is, between two users using the app at the same time) if the insertion or deletion causes the pagination to be off for another user.
|
867
|
+
|
868
|
+
|
869
|
+
### `--alt-foreign-key-lookup` (Foreign Key Lookups)
|
870
|
+
|
871
|
+
`--alt-foreign-key-lookup=user_id{email}`
|
872
|
+
|
873
|
+
Let's assume a `Company` `has_many :company_users` and also a `Company` `has_many :users, through: :company_users`
|
874
|
+
|
875
|
+
Normally, you would be constructing a CompanyUsers downnest portal on the Company page. (Showing you only CompanyUsers associated with that company.)
|
876
|
+
|
877
|
+
A drop down of _all users in the_ database will be display on the screen where you create a new CompanyUser (join) record.
|
878
|
+
|
879
|
+
Let's say instead you don't want to expose the full list of all users to this controller, but instead make your user enter the full email address of the user to identify them.
|
880
|
+
|
881
|
+
Instead of a drop-down, the interface will present an input box for the user to supply an *search by* email.
|
882
|
+
|
883
|
+
** Note: Current implementation does not work in conjunction with hawked associations to protect against users from accessing associated records not within scope.**
|
884
|
+
TODO: make it work with hawked associations to protect against users from accessing associated records not within scope
|
885
|
+
|
886
|
+
|
887
|
+
## "Thing" Label
|
888
|
+
|
889
|
+
Note that on a per model basis, you can also globally omit the label or set a unique label value using
|
890
|
+
`@@table_label_singular` and `@@table_label_plural` on your model objects.
|
818
891
|
|
819
|
-
|
820
|
-
|
892
|
+
You have three options to specify labels explicitly with a string, and 1 option to specify a global name for which the words "Delete ___" and "New ___" will be added.
|
893
|
+
|
894
|
+
If no `--label` is specified, it will be inferred to be the Capitalized version of the name of the thing you are building, with spaces for two or more words.
|
895
|
+
|
896
|
+
### `--label`
|
897
|
+
|
898
|
+
The general name of the thing, will be applied as "New ___" for the new button & form. Will be *pluralized* for list label heading, so if the word has a non-standard pluralization, be sure to specify it in `config/inflictions.rb`
|
899
|
+
|
900
|
+
If you specify anything explicitly, it will be used.
|
901
|
+
If not, a specification that exists as `@@tabel_label_singular` from the Model will be used.
|
902
|
+
If this does not exist, the Titleized (capitalized) version of the model name.
|
903
|
+
|
904
|
+
### `--list-label-heading`
|
905
|
+
The plural of the list of things at the top of the list.
|
906
|
+
If not, a specification that exists as `@@tabel_label_plural` from the Model will be used.
|
907
|
+
If this does not exist, the UPCASE (all-uppercase) version of the model name.
|
908
|
+
|
909
|
+
### `--new-button-label`
|
910
|
+
The button on the list that the user clicks onto to create a new record.
|
911
|
+
(Follows same rules described in the `--label` option but with the word "New" prepended.)
|
912
|
+
|
913
|
+
### `--new-form-heading`
|
914
|
+
The text at the top of the new form that appears when the new input entry is displayed.
|
915
|
+
(Follows same rules described in the `--label` option but with the word "New" prepended.)
|
916
|
+
|
917
|
+
### `--no-list-label`
|
918
|
+
Omits list LABEL itself above the list. (Do not confuse with the list heading which contains the field labels.)
|
821
919
|
|
822
920
|
Note that list labels may be automatically omitted on downnested scaffolds.
|
823
921
|
|
922
|
+
|
923
|
+
|
924
|
+
|
925
|
+
## Field Labels
|
926
|
+
|
927
|
+
### `--form-labels-position` (default: `after`; options are **before**, **after**, and **omit**)
|
928
|
+
By default form labels appear after the form inputs. To make them appear before or omit them, use this flag.
|
929
|
+
|
930
|
+
See also `--form-placeholder-labels` to use placeolder labels.
|
931
|
+
|
932
|
+
|
824
933
|
### `--form-placeholder-labels` (default: false)
|
825
934
|
|
826
935
|
When set to true, fields, numbers, and text areas will have placeholder labels.
|
@@ -841,39 +950,85 @@ Use `before` to make the labels come before or `after` to make them come after.
|
|
841
950
|
|
842
951
|
Omits the heading of column names that appears above the 1st row of data.
|
843
952
|
|
844
|
-
### `--no-create`
|
845
953
|
|
846
|
-
Omits new & create actions.
|
847
954
|
|
848
|
-
### `--no-delete`
|
849
955
|
|
850
|
-
Omits delete button & destroy action.
|
851
956
|
|
852
|
-
|
957
|
+
## Special Features
|
853
958
|
|
854
|
-
|
959
|
+
### `--alt-lookup-foreign-keys`
|
855
960
|
|
856
|
-
|
961
|
+
Allows you to specify that a foreign key should act as a search field, allowing the user to input a unique value (like an email) to search for a related record.
|
857
962
|
|
858
|
-
|
963
|
+
Example:
|
964
|
+
```
|
965
|
+
--alt-foreign-key-lookup='agent_id{email+}'
|
966
|
+
```
|
859
967
|
|
860
|
-
|
968
|
+
First, assume the current able has a `belongs_to` association for `agent_id` to a foreign model, `Agent`
|
861
969
|
|
862
|
-
|
970
|
+
Here, we would build a scaffold that would treat the foreign key `agent_id` as an alt lookup, allowing the user to search for foreign records by email (the agent's email).
|
863
971
|
|
864
|
-
|
972
|
+
The `+` symbol indicates to automatically make a new `agent` record (without it, the agent_id will be set to nil if there is no associated agent record found -- this may cause the update to fail, unless `optional: true` is on the belongs_to association.)
|
865
973
|
|
866
|
-
If and only if you specify `--with-turbo-streams`, your views will contain `turbo_stream_from` directives. Whereas your views will always contain `turbo_frame_tags` (wether or not this flag is specified) and will use the Turbo stream replacement mechanism for non-idempotent actions (create & update). This flag just brings the magic of live-reload to the scaffold interfaces themselves.
|
867
974
|
|
868
|
-
|
975
|
+
### `--factory-creation={ ... }`
|
869
976
|
|
870
|
-
|
977
|
+
The code you specify inside of `{` and `}` will be used to generate a new object. The factory should instantiate with any arguments (I suggest Ruby keyword arguments) and must provide a method that is the name of the thing.
|
978
|
+
|
979
|
+
For example, a user Factory might be called like so:
|
980
|
+
|
981
|
+
`rails generate hot_glue:scaffold User --factory-creation={factory = UserFactory.new(params: user_params)} --gd`
|
982
|
+
|
983
|
+
(Note we are relying on the `user_params` method provided by the controller.)
|
984
|
+
|
985
|
+
You must do one of two things:
|
986
|
+
1) In the code you specify, set an instance variable `@user` to be the newly created thing. (Your code should contain something like `@thing = ` to trigger this option.)
|
987
|
+
2) Make a local variable called `factory` **and** have a method of the name of the object (`user`) on a local variable called `factory` that your code created
|
988
|
+
|
989
|
+
(The code example above is the option for #2 because it does not contain `@user =`)
|
990
|
+
|
991
|
+
If using number #2, Hot Glue will append this to the code specified:
|
992
|
+
```
|
993
|
+
@user = factory.user
|
994
|
+
```
|
995
|
+
|
996
|
+
|
997
|
+
Here's a sample UserFactory that will create a new user only if one with a matching email address doesn't exist. (Otherwise, it will update the existing record.)
|
998
|
+
Your initialize method can take any params you need it to, and using this pattern your business logic is applied consistently throughout your app. (You must, of course, use your Factory everywhere else in your app too.)
|
999
|
+
|
1000
|
+
```
|
1001
|
+
class UserFactory
|
1002
|
+
attr_reader :user
|
1003
|
+
attr_accessor :email
|
1004
|
+
|
1005
|
+
def initialize(params: {})
|
1006
|
+
user = User.find_or_create_by(email: params[:email])
|
1007
|
+
|
1008
|
+
user.update(params)
|
1009
|
+
if user.new_record?
|
1010
|
+
# do special new user logic here, like sending an email
|
1011
|
+
end
|
1012
|
+
end
|
1013
|
+
end
|
1014
|
+
```
|
1015
|
+
|
1016
|
+
|
1017
|
+
If you are using factory creation along with with alt lookups, be sure your factory code creates a local variable that follows this name
|
1018
|
+
|
1019
|
+
**<downcase association name>**_factory.<downcase association name>
|
1020
|
+
|
1021
|
+
Thus, your factory object must have a method of the same name as the factory being created which returns the thing that got created.
|
1022
|
+
(It can do the creation either on instantiation or when calling that method)
|
1023
|
+
|
1024
|
+
For example, assuming the example from above, we are going to do the lookup ourselves inside of our own `AgentFactory` object.)
|
1025
|
+
|
1026
|
+
```
|
1027
|
+
agent_factory = AgentFactory.new(find_or_create_by_email: agent_company_params[:__lookup_email])
|
1028
|
+
```
|
871
1029
|
|
872
|
-
1) by default, all Hot Glue scaffold is wrapped in `turbo_frame_tag`s. The id of these tags is your namespace + the Rails dom_id(...). That means all Hot Glue scaffold is namespaced to the namespaces you use and won't collide with other turbo_frame_tag you might be using elsewhere
|
873
1030
|
|
874
|
-
2) by appending **model callbacks**, we can automatically broadcast updates to the users who are using the Hot Glue scaffold. The model callbacks (after_update_commit and after_destroy_commit) get appended automatically to the top of your model file. Each model callback targets the scaffold being built (so just this scaffold), using its namespace, and renders the line partial (or destroys the content in the case of delete) from the scaffolding.
|
875
1031
|
|
876
|
-
please note that *creating* and *deleting* do not yet have a full & complete implementation: Your pages won't re-render the pages being viewed cross-peer (that is, between two users using the app at the same time) if the insertion or deletion causes the pagination to be off for another user.
|
877
1032
|
|
878
1033
|
|
879
1034
|
## Automatic Base Controller
|
@@ -897,8 +1052,10 @@ Child portals have the headings omitted automatically (there is a heading identi
|
|
897
1052
|
## Field Types Supported
|
898
1053
|
|
899
1054
|
- Integers that don't end with `_id`: displayed as input fields with type="number"
|
900
|
-
- Foreign
|
1055
|
+
- Foreign key integers: 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.)
|
901
1056
|
- Note: if your foreign key has a nonusual class name, it should be using the `class_name:` in the model definition
|
1057
|
+
- UUIDs (as primary key): Works seamlessly for the `id` field to make your primary key a UUID (Be sure to specify UUID in your model's migration).
|
1058
|
+
- UUIDs (as foreign key): All UUIDs that are not named `id` are assumed to be foreign keys and will be treated as associations.
|
902
1059
|
- String: displayed as small input box
|
903
1060
|
- Text: displayed as large textarea
|
904
1061
|
- Float: displayed as input box
|
@@ -908,10 +1065,108 @@ Child portals have the headings omitted automatically (there is a heading identi
|
|
908
1065
|
- Boolean: displayed radio buttons yes/ no
|
909
1066
|
- Enum - displayed as a drop-down list (defined the enum values on your model).
|
910
1067
|
- For Rails 6 see https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
|
911
|
-
-
|
1068
|
+
- You must specify the enum definition both in your model and also in your database migration for both Rails 6 + Rails 7
|
1069
|
+
|
1070
|
+
# Note about enums
|
1071
|
+
|
1072
|
+
The Rails 7 enum implementation for Postgres is very slick but has a counter-intuitive facet.
|
1073
|
+
Define your Enums in Postgres as strings:
|
1074
|
+
(database migration)
|
1075
|
+
```
|
1076
|
+
create_enum :status, ["pending", "active", "archived"]
|
1077
|
+
|
1078
|
+
create_table :users, force: true do |t|
|
1079
|
+
t.enum :status, enum_type: "status", default: "pending", null: false
|
1080
|
+
t.timestamps
|
1081
|
+
end
|
1082
|
+
```
|
1083
|
+
|
1084
|
+
Then define your `enum` ActiveRecord declaration with duplicate keys & strings:
|
1085
|
+
(model definition)
|
1086
|
+
```
|
1087
|
+
enum status: {
|
1088
|
+
pending: "pending",
|
1089
|
+
active: "active",
|
1090
|
+
archived: "archived",
|
1091
|
+
disabled: "disabled",
|
1092
|
+
waiting: "waiting"
|
1093
|
+
}
|
1094
|
+
```
|
1095
|
+
|
1096
|
+
To set the labels, use another class-level method that is a hash of keys-to-labels using a method named the same name as the enum method but with `_labels`
|
1097
|
+
|
1098
|
+
If no `_labels` method exists, Hot Glue will fallback to using the Postgres-defined names.
|
1099
|
+
```
|
1100
|
+
def self.status_labels
|
1101
|
+
{
|
1102
|
+
pending: 'Is Pending',
|
1103
|
+
active: 'Is active',
|
1104
|
+
archived: 'Is Archived',
|
1105
|
+
disabled: 'Is Disabled',
|
1106
|
+
waiting: 'Is Waiting'
|
1107
|
+
}
|
1108
|
+
```
|
1109
|
+
|
1110
|
+
Now, your labels will show up as defined in the `_labels` ("Is Pending", etc) instead of the database-values.
|
912
1111
|
|
913
1112
|
|
914
1113
|
# VERSION HISTORY
|
1114
|
+
#### 2023-03-01 - v0.5.8
|
1115
|
+
|
1116
|
+
• Fixes spec assertions for enums to work with the enum `_label` field (when provided).
|
1117
|
+
|
1118
|
+
• Fixes `--form-label-position` (before/after) so that a carriage return is placed between the label & field correctly for either choice
|
1119
|
+
|
1120
|
+
• All spec files are now created in `spec/features/` folder (previously was `spec/system/` with `type: :feature`; they no longer have `type: :feature` as this is not necessary when they are in the `spec/features` folder)
|
1121
|
+
|
1122
|
+
• Corrects the hawk scope to only add the plural related entity when NOT using the shorthand `{ ... }`
|
1123
|
+
|
1124
|
+
• BEM (block element modifier)-style has been added list headings, show cells, edit cells. These class names will get added to the `<div>` tags for both the heading and cells.
|
1125
|
+
|
1126
|
+
The format is as follows:
|
1127
|
+
|
1128
|
+
For headings
|
1129
|
+
`heading--{singular}--{field name}-{field name}-{field name}`
|
1130
|
+
|
1131
|
+
For cells:
|
1132
|
+
`cell--{singular}--{field name}-{field name}-{field name}`
|
1133
|
+
use this to globally style different fields by object & field name
|
1134
|
+
|
1135
|
+
Note that if you have multiple fields inside one cell (for example, with specified grouping or smart layout), your fields names get concatinated using single-hyphens:
|
1136
|
+
For example, consider a customer scaffold with a first name & last name appearing in one cell. The cell itself will have a class of:
|
1137
|
+
`cell--customer--first_name-last_name`
|
1138
|
+
|
1139
|
+
If your cell contains only one field, for example, a phone number, it would look like this:
|
1140
|
+
`cell--customer--phone_number`
|
1141
|
+
|
1142
|
+
Tip: Use the _ends with_ and _starts with_ selectors, which can be used like this:.
|
1143
|
+
|
1144
|
+
```
|
1145
|
+
div[class$="--phone_number"] {
|
1146
|
+
text-decoration: underline;
|
1147
|
+
}
|
1148
|
+
```
|
1149
|
+
|
1150
|
+
|
1151
|
+
```
|
1152
|
+
|
1153
|
+
```
|
1154
|
+
|
1155
|
+
|
1156
|
+
#### 2023-02-13 - v0.5.7 - factory-creation, alt lookups, update show only, fixes to Enums, support for Ruby 3.2
|
1157
|
+
• See `--factory-creation` section.
|
1158
|
+
|
1159
|
+
• `--alt-lookup-foreign-keys`
|
1160
|
+
Allows you to specify that a foreign key should act as a search field, allowing the user to input a unique value (like an email) to search for a related record.
|
1161
|
+
|
1162
|
+
• `--update-show-only`
|
1163
|
+
Allows you to specify a list fields that should be show-only (non-editable) on the **edit** page but remain inputable on the **create** page.
|
1164
|
+
Note that a singular partial `_form` is still used for new & edit, but now contains `if` statements that check the action and display the show-only version only on the edit action.
|
1165
|
+
|
1166
|
+
• Syntax fix to support Ruby 3.2.0 (the installer was broken if you used Ruby 3.2)
|
1167
|
+
|
1168
|
+
• Tweaks to how Enums are display (see "Note about Enums")
|
1169
|
+
|
915
1170
|
|
916
1171
|
#### 2023-01-02 - v0.5.6
|
917
1172
|
- Changes the long-form of the hawk specifier to require you to use the has_many of the relationship you are hawking (previously, it was assumed). See Hawk for details
|
@@ -962,8 +1217,8 @@ License check has been removed (Hot Glue is now free to use for hobbyists and in
|
|
962
1217
|
#### 2022-03-23 - v0.5.2 - Hawked Foreign Keys
|
963
1218
|
|
964
1219
|
- You can now protect your foreign keys from malicious input and also restrict the scope of drop downs to show only records with the specified access control restriction.
|
965
|
-
- [Example #3](https://
|
966
|
-
- [Example #4](https://
|
1220
|
+
- [Example #3](https://school.jasonfleetwoodboldt.com/8188) in the Hot Glue Tutorial shows you how to use the hawk to limit the scope to the logged in user.
|
1221
|
+
- [Example #4](https://school.jasonfleetwoodboldt.com/8188) in the Hot Glue Tutorial shows how to hawk to a non-usual scope, the inverse of the current user's belongs_to (that is, hawk the scope to X where current_user `belongs_to :x`)
|
967
1222
|
|
968
1223
|
|
969
1224
|
#### 2022-03-12 - v0.5.1 - Inline List Labels
|
@@ -1133,9 +1388,9 @@ This runs both the **generated specs** and also the **internal specs**. Examine
|
|
1133
1388
|
|
1134
1389
|
To run only the internal specs, use
|
1135
1390
|
|
1136
|
-
`
|
1391
|
+
`rspec spec`
|
1137
1392
|
|
1138
|
-
Internal Test coverage as of
|
1393
|
+
Internal Test coverage as of 2023-02-10 (v0.5.7)
|
1139
1394
|
|
1140
|
-
|
1395
|
+
<img width="1202" alt="Screen Shot 2023-02-10 at 4 43 59 PM" src="https://user-images.githubusercontent.com/59002/218204736-5740505b-1ec8-456f-b0fb-9c359f6f7037.png">
|
1141
1396
|
|
@@ -119,7 +119,7 @@ module HotGlue
|
|
119
119
|
|
120
120
|
|
121
121
|
begin
|
122
|
-
if !File.
|
122
|
+
if !File.exist?("#{'spec/dummy/' if Rails.env.test?}config/hot_glue.yml")
|
123
123
|
yaml = {layout: layout,
|
124
124
|
markup: @markup}.to_yaml
|
125
125
|
File.write("#{'spec/dummy/' if Rails.env.test?}config/hot_glue.yml", yaml)
|
@@ -131,7 +131,7 @@ module HotGlue
|
|
131
131
|
|
132
132
|
|
133
133
|
begin
|
134
|
-
if !File.
|
134
|
+
if !File.exist?("#{'spec/dummy/' if Rails.env.test?}spec/support/capybara_login.rb")
|
135
135
|
copy_file "capybara_login.rb", "#{'spec/dummy/' if Rails.env.test?}spec/support/capybara_login.rb"
|
136
136
|
end
|
137
137
|
rescue StandardError => e
|
@@ -79,14 +79,18 @@ module HotGlue
|
|
79
79
|
layout_object[:columns][:container] = (0..available_columns-1).collect { |x|
|
80
80
|
[ columns[x]]
|
81
81
|
}
|
82
|
+
layout_object[:columns][:container] = (0..available_columns-1).collect { |x| [columns[x]] }
|
82
83
|
layout_object[:columns][:container].reject!{|x| x == [nil]}
|
84
|
+
layout_object[:columns][:size_each] = 2
|
83
85
|
end
|
84
86
|
elsif ! specified_grouping_mode
|
85
87
|
# not smart and no specified grouping
|
86
|
-
|
88
|
+
layout_object[:columns][:button_columns] = 2
|
89
|
+
|
87
90
|
layout_object[:columns][:container] = columns.collect{|col| [col]}
|
88
91
|
|
89
92
|
else # specified grouping mode -- the builder is given control
|
93
|
+
layout_object[:columns][:button_columns] = 2
|
90
94
|
|
91
95
|
(0..available_columns-1).each do |int|
|
92
96
|
layout_object[:columns][:container][int] = []
|
@@ -129,7 +133,7 @@ module HotGlue
|
|
129
133
|
# # give some space back to the downnest
|
130
134
|
# end
|
131
135
|
|
132
|
-
puts "*** constructed layout columns #{layout_object.inspect}"
|
136
|
+
puts "*** constructed smart layout columns #{layout_object.inspect}"
|
133
137
|
layout_object
|
134
138
|
end
|
135
139
|
|
@@ -1,8 +1,22 @@
|
|
1
1
|
class LayoutStrategy::Bootstrap < LayoutStrategy::Base
|
2
|
-
def button_classes
|
3
|
-
" " +
|
2
|
+
def button_classes # column classes
|
3
|
+
" " + "col-sm-#{builder.layout_object[:columns][:button_columns]}"
|
4
4
|
end
|
5
5
|
|
6
|
+
def button_applied_classes
|
7
|
+
"btn btn-sm"
|
8
|
+
end
|
9
|
+
|
10
|
+
def magic_button_classes
|
11
|
+
"btn-secondary"
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def column_classes_for_button_column
|
16
|
+
"col-md-#{builder.layout_object[:buttons][:size]}"
|
17
|
+
end
|
18
|
+
|
19
|
+
|
6
20
|
def column_classes_for_form_fields
|
7
21
|
"col-md-#{builder.layout_object[:columns][:size_each]}"
|
8
22
|
end
|
@@ -12,7 +26,7 @@ class LayoutStrategy::Bootstrap < LayoutStrategy::Base
|
|
12
26
|
end
|
13
27
|
|
14
28
|
def container_name
|
15
|
-
"container
|
29
|
+
"container"
|
16
30
|
end
|
17
31
|
|
18
32
|
def column_classes_for_line_fields
|