hot-glue 0.0.7 → 0.1.2
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/Gemfile.lock +19 -17
- data/README.md +93 -49
- data/db/migrate/20210306223305_create_ghis.rb +9 -0
- data/db/schema.rb +1 -1
- data/lib/generators/hot_glue/scaffold_generator.rb +114 -89
- data/lib/generators/hot_glue/templates/_form.haml +1 -0
- data/lib/generators/hot_glue/templates/_new_form.haml +0 -3
- data/lib/generators/hot_glue/templates/_show.haml +2 -2
- data/lib/generators/hot_glue/templates/controller.rb.erb +12 -10
- data/lib/generators/hot_glue/templates/system_spec.rb.erb +115 -76
- data/lib/generators/hot_glue/templates/update.turbo_stream.haml +4 -0
- data/lib/hotglue/version.rb +1 -1
- metadata +11 -12
- data/db/migrate/20210306223305_create_hgis.rb +0 -9
- data/lib/generators/hot_glue/templates/request_spec.rb.erb +0 -110
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3b265c8c7f5e9fb424122d2d40eec712a7cb4f846f5daf581b75a8e4981790fa
|
4
|
+
data.tar.gz: 23e8b5857b4e8fa2391a46128a282a952355fe64c9097868b98bf8d462c9a35c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3a304db4b93d3edf92657178e0057830f224dda0e1b08c5957169d2e6f378ac6cc9137513e18001c38881d7f2594d2d608ba3de07ffa86291089c01cccecc462
|
7
|
+
data.tar.gz: 884d154c85a9688b66db56498f2f66dbda7356d06d2f5590e80c911f86e46fee5bcefc1809f6d5deb339b79fe95a95d45f823a89128105ec367f0d7b6c67a85d
|
data/.github/FUNDING.yml
CHANGED
@@ -1,2 +1,2 @@
|
|
1
1
|
github: [jasonfb]
|
2
|
-
custom: ["https://
|
2
|
+
custom: ["https://www.instagram.com/jfbcodes/"]
|
data/Gemfile.lock
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
hot-glue (0.
|
4
|
+
hot-glue (0.1.1)
|
5
5
|
ffaker (~> 2.16)
|
6
6
|
haml-rails (~> 2.0)
|
7
7
|
kaminari (~> 1.2)
|
@@ -74,9 +74,9 @@ GEM
|
|
74
74
|
bcrypt (3.1.16)
|
75
75
|
builder (3.2.4)
|
76
76
|
byebug (11.1.3)
|
77
|
-
concurrent-ruby (1.1.
|
77
|
+
concurrent-ruby (1.1.9)
|
78
78
|
crass (1.0.6)
|
79
|
-
devise (4.
|
79
|
+
devise (4.8.0)
|
80
80
|
bcrypt (~> 3.0)
|
81
81
|
orm_adapter (~> 0.1)
|
82
82
|
railties (>= 4.1.0)
|
@@ -85,7 +85,7 @@ GEM
|
|
85
85
|
erubi (1.10.0)
|
86
86
|
erubis (2.7.0)
|
87
87
|
ffaker (2.18.0)
|
88
|
-
ffi (1.
|
88
|
+
ffi (1.15.3)
|
89
89
|
globalid (0.4.2)
|
90
90
|
activesupport (>= 4.2.0)
|
91
91
|
haml (5.2.1)
|
@@ -102,7 +102,7 @@ GEM
|
|
102
102
|
haml (>= 4.0, < 6)
|
103
103
|
nokogiri (>= 1.6.0)
|
104
104
|
ruby_parser (~> 3.5)
|
105
|
-
i18n (1.8.
|
105
|
+
i18n (1.8.10)
|
106
106
|
concurrent-ruby (~> 1.0)
|
107
107
|
kaminari (1.2.1)
|
108
108
|
activesupport (>= 4.1.0)
|
@@ -116,7 +116,7 @@ GEM
|
|
116
116
|
activerecord
|
117
117
|
kaminari-core (= 1.2.1)
|
118
118
|
kaminari-core (1.2.1)
|
119
|
-
loofah (2.
|
119
|
+
loofah (2.10.0)
|
120
120
|
crass (~> 1.0.2)
|
121
121
|
nokogiri (>= 1.5.9)
|
122
122
|
mail (2.7.1)
|
@@ -124,12 +124,14 @@ GEM
|
|
124
124
|
marcel (0.3.3)
|
125
125
|
mimemagic (~> 0.3.2)
|
126
126
|
method_source (1.0.0)
|
127
|
-
mimemagic (0.3.
|
128
|
-
|
129
|
-
|
127
|
+
mimemagic (0.3.10)
|
128
|
+
nokogiri (~> 1)
|
129
|
+
rake
|
130
|
+
mini_mime (1.1.0)
|
131
|
+
mini_portile2 (2.5.3)
|
130
132
|
minitest (5.14.4)
|
131
133
|
nio4r (2.5.7)
|
132
|
-
nokogiri (1.11.
|
134
|
+
nokogiri (1.11.7)
|
133
135
|
mini_portile2 (~> 2.5.0)
|
134
136
|
racc (~> 1.4)
|
135
137
|
orm_adapter (0.5.0)
|
@@ -167,8 +169,8 @@ GEM
|
|
167
169
|
responders (3.0.1)
|
168
170
|
actionpack (>= 5.0)
|
169
171
|
railties (>= 5.0)
|
170
|
-
ruby_parser (3.
|
171
|
-
sexp_processor (~> 4.
|
172
|
+
ruby_parser (3.16.0)
|
173
|
+
sexp_processor (~> 4.15, >= 4.15.1)
|
172
174
|
sass-rails (6.0.0)
|
173
175
|
sassc-rails (~> 2.1, >= 2.1.1)
|
174
176
|
sassc (2.4.0)
|
@@ -179,7 +181,7 @@ GEM
|
|
179
181
|
sprockets (> 3.0)
|
180
182
|
sprockets-rails
|
181
183
|
tilt
|
182
|
-
sexp_processor (4.15.
|
184
|
+
sexp_processor (4.15.3)
|
183
185
|
sprockets (4.0.2)
|
184
186
|
concurrent-ruby (~> 1.0)
|
185
187
|
rack (> 1, < 3)
|
@@ -191,19 +193,19 @@ GEM
|
|
191
193
|
temple (0.8.2)
|
192
194
|
thor (1.1.0)
|
193
195
|
tilt (2.0.10)
|
194
|
-
turbo-rails (0.5.
|
196
|
+
turbo-rails (0.5.11)
|
195
197
|
rails (>= 6.0.0)
|
196
198
|
tzinfo (2.0.4)
|
197
199
|
concurrent-ruby (~> 1.0)
|
198
200
|
warden (1.2.9)
|
199
201
|
rack (>= 2.0.9)
|
200
|
-
websocket-driver (0.7.
|
202
|
+
websocket-driver (0.7.5)
|
201
203
|
websocket-extensions (>= 0.1.0)
|
202
204
|
websocket-extensions (0.1.5)
|
203
205
|
zeitwerk (2.4.2)
|
204
206
|
|
205
207
|
PLATFORMS
|
206
|
-
|
208
|
+
-darwin-20
|
207
209
|
|
208
210
|
DEPENDENCIES
|
209
211
|
byebug
|
@@ -213,4 +215,4 @@ DEPENDENCIES
|
|
213
215
|
sqlite3
|
214
216
|
|
215
217
|
BUNDLED WITH
|
216
|
-
2.
|
218
|
+
2.2.19
|
data/README.md
CHANGED
@@ -1,72 +1,118 @@
|
|
1
1
|
# Hot Glue
|
2
2
|
|
3
|
-
Hot Glue is
|
3
|
+
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)).
|
4
4
|
|
5
|
-
|
5
|
+
Using Turbo-Rails and Hotwire you get a lightning-fast out-of-the-box CRUD building experience. Every page displays only a list view: new and edit operations happen as 'edit-in-place', so the user never leaves the page.
|
6
6
|
|
7
|
-
It
|
7
|
+
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.
|
8
8
|
|
9
|
-
|
9
|
+
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.
|
10
10
|
|
11
|
-
|
12
|
-
|
13
|
-
*
|
14
|
-
*
|
15
|
-
*
|
11
|
+
Hot Glue generates functionality that's quick and dirty. It let's you be crafty. As with a real hot glue gun, use with caution.
|
12
|
+
|
13
|
+
* Build plug-and-play scaffolding for any CRUD on any object
|
14
|
+
* mixes HAML and turbo_stream responses
|
15
|
+
* Everything edits-in-place (unless you use --big-edit, then it won't)
|
16
|
+
* Automatically reads your ActiveRecord models and relationships (make them before building your scaffolding!)
|
17
|
+
* Create-read-update-delete (CRUD) with pagination (one day: sorting & searching)
|
18
|
+
* Excellent tool for prototyping and hackathons, but a knowledge of Rails is needed.
|
19
|
+
* Nest your routes model-by-model for built-in poor man's authentication. (Customers have_many :invoices; Invoices have_many :line_items; etc)
|
16
20
|
* Plays nicely with Devise, but you can implement your own current_user object instead.
|
17
|
-
*
|
18
|
-
* Create specs automatically along with the controllers
|
21
|
+
* Kaminari for pagination.
|
22
|
+
* Create specs automatically along with the controllers.
|
19
23
|
* Throw the scaffolding away when your app is ready to graduate to its next phase (or don't if you like it).
|
20
24
|
|
21
|
-
## QUICK START
|
25
|
+
## QUICK START
|
22
26
|
|
23
27
|
It's really easy to get started by following along with this blog post that creates three simple tables (User, Event, and Format).
|
24
28
|
|
25
29
|
Feel free to build your own tables when you get to the sections for building the 'Event' scaffold:
|
26
30
|
|
27
|
-
https://
|
31
|
+
https://jasonfleetwoodboldt.com/hot-glue
|
28
32
|
|
29
33
|
## HOW EASY?
|
30
34
|
|
31
|
-
|
32
35
|
```
|
33
36
|
rails generate hot_glue:scaffold Thing
|
34
37
|
```
|
35
38
|
|
39
|
+
Generate a quick scaffold to manage a table called `pronouns`
|
40
|
+
![hot-glue-3](https://user-images.githubusercontent.com/59002/116405509-bdee2f00-a7fd-11eb-9723-4c6e22f81bd3.gif)
|
41
|
+
|
42
|
+
|
43
|
+
|
44
|
+
Instantly get a simple CRUD interface
|
45
|
+
|
46
|
+
![hot-glue-4](https://user-images.githubusercontent.com/59002/116405517-c2b2e300-a7fd-11eb-8423-d43e3afc9fa6.gif)
|
47
|
+
|
48
|
+
|
36
49
|
## TO INSTALL
|
37
50
|
|
38
|
-
- Add
|
51
|
+
- Add `gem 'turbo-rails'` to your Gemfile & `bundle install`
|
52
|
+
|
53
|
+
- Then install it with `rails turbo:install`
|
39
54
|
|
40
55
|
- The Turbo install has switched your action cable settings from 'async' to Redis, so be sure to start a redis server
|
41
56
|
|
42
|
-
- Add
|
57
|
+
- Add `gem 'hot-glue'` to your Gemfile & `bundle install`
|
58
|
+
|
59
|
+
- Run the hot-glue installation with `rails generate hot_glue:install`
|
43
60
|
|
44
61
|
- Add to your `application.html.erb`
|
45
62
|
```
|
46
63
|
<%= render partial: 'layouts/flash_notices' %>
|
47
64
|
```
|
48
65
|
|
66
|
+
- Rspec setup
|
67
|
+
- add `gem 'rspec-rails'` to your gemfile inside :development and :test
|
68
|
+
- add `gem 'factory_bot_rails'` to your gemfile inside :development and :test
|
69
|
+
- run `rails generate rspec:install`
|
70
|
+
- configure Rspec to work with Factory Bot inside of `rails_helper.rb`
|
71
|
+
```
|
72
|
+
RSpec.configure do |config|
|
73
|
+
// ... more rspec configuration (not shown)
|
74
|
+
config.include FactoryBot::Syntax::Methods
|
75
|
+
end
|
76
|
+
```
|
77
|
+
more info:
|
78
|
+
https://github.com/thoughtbot/factory_bot/blob/master/GETTING_STARTED.md#rspec
|
79
|
+
|
80
|
+
- for a quick Capybara login, create a support helper in `spec/support/` and log-in as your user
|
81
|
+
```
|
82
|
+
def login_as(account)
|
83
|
+
visit '/accounts/sign_in'
|
84
|
+
within("#new_account") do
|
85
|
+
fill_in 'Email', with: account.email
|
86
|
+
fill_in 'Password', with: 'password'
|
87
|
+
end
|
88
|
+
click_button 'Log in'
|
89
|
+
end
|
90
|
+
```
|
91
|
+
|
49
92
|
- Install Bootstrap (optional)
|
50
93
|
|
51
94
|
Bootstrap with Webpack:
|
52
95
|
- change `stylesheet_link_tag` to `stylesheet_pack_tag` in your application layout
|
53
|
-
- `yarn add bootstrap`
|
54
|
-
- create a new file at `app/javascript/
|
96
|
+
- run `yarn add bootstrap`
|
97
|
+
- create a new file at `app/javascript/require_bootstrap.scss` with this content
|
55
98
|
```
|
56
99
|
@import "~bootstrap/scss/bootstrap.scss";
|
57
100
|
```
|
58
101
|
|
59
102
|
- add to `app/javascript/packs/application.js`
|
60
103
|
```
|
61
|
-
import '
|
104
|
+
import 'require_bootstrap'
|
62
105
|
```
|
63
106
|
|
64
107
|
Bootstrap with Sprockets:
|
65
|
-
- use bootstrap-
|
66
|
-
|
108
|
+
- use bootstrap-rubygem gem
|
109
|
+
- see README for bootstrap-rubygem to install
|
110
|
+
|
67
111
|
|
68
112
|
- Install Devise or implement your own authentication
|
113
|
+
(or only use --gd mode, see below)
|
69
114
|
|
115
|
+
- font-awesome
|
70
116
|
|
71
117
|
|
72
118
|
### First Argument
|
@@ -225,7 +271,7 @@ Please note that this example would product non-functional code, so you would ne
|
|
225
271
|
|
226
272
|
### `--plural=`
|
227
273
|
|
228
|
-
You don't need this if the pluralized version is just + "s" of the singular version. Only use for non-standard plurlizations, and be sure to pass it as TitleCase (as if
|
274
|
+
You don't need this if the pluralized version is just + "s" of the singular version. Only use for non-standard plurlizations, and be sure to pass it as TitleCase (as if you pluralized the model name which is non-standard for Rails)
|
229
275
|
|
230
276
|
|
231
277
|
### `--exclude=`
|
@@ -249,13 +295,22 @@ You may not specify both include and exclude. If you specify an include list, it
|
|
249
295
|
`rails generate hot_glue:scaffold Account --include=first_name,last_name,company_name,created_at,kyc_verified_at`
|
250
296
|
|
251
297
|
|
298
|
+
### `--show-only=`
|
299
|
+
(separate field names by COMMA)
|
300
|
+
|
301
|
+
Any fields only the 'show-only' list will appear as non-editable on the generate form. (visible only)
|
302
|
+
|
303
|
+
IMPORTANT: By default, all fields that begin with an underscore (`_`) are automatically show-only.
|
304
|
+
|
305
|
+
I would recommend this 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.
|
306
|
+
|
252
307
|
### `--god` or `--gd`
|
253
308
|
|
254
309
|
Use this flag to create controllers with no root authentication. You can still use an auth_identifier, which can be useful for a meta-leval authentication to the controller.
|
255
310
|
|
256
311
|
For example, FOR ADMIN CONTROLLERS ONLY, supply a auth_identifier and use `--god` flag.
|
257
312
|
|
258
|
-
In
|
313
|
+
In Gd mode, the objects are loaded directly from the base class (these controllers have full access)
|
259
314
|
```
|
260
315
|
def load_thing
|
261
316
|
@thing = Thing.find(params[:id])
|
@@ -295,8 +350,19 @@ If you do not want inline editing of your list items but instead to fall back to
|
|
295
350
|
|
296
351
|
|
297
352
|
|
353
|
+
|
354
|
+
|
298
355
|
# VERSION HISTORY
|
299
356
|
|
357
|
+
#### - v0.1.1 -
|
358
|
+
|
359
|
+
|
360
|
+
#### 2021-04-28 - v0.1.0 - Very pleased to introduce full behavior specs, found in specs/system/, generated by default on all build code; also many fixes involving nesting and authentication"
|
361
|
+
|
362
|
+
#### 2021-03-24 - v0.0.9 - fixes in the automatic field label detection; cleans up junk in spec output
|
363
|
+
|
364
|
+
#### 2021-03-21 - v0.0.8 - show only flag; more specific spec coverage in generator spec
|
365
|
+
|
300
366
|
#### 2021-03-20 - v0.0.7 - adds lots of spec coverage; cleans up generated cruft code on each run; adds no-delete, no-create; a working --big-edit with basic data-turbo false to disable inline editing
|
301
367
|
|
302
368
|
#### 2021-03-06 - v0.0.6 - internal specs test the error catches and cover basic code generation (dummy testing only)
|
@@ -314,41 +380,19 @@ If you do not want inline editing of your list items but instead to fall back to
|
|
314
380
|
#### 2021-02-23 - v0.0.0 - Port of my prior work from github.com/jasonfb/common_core_js
|
315
381
|
|
316
382
|
|
317
|
-
# ACKNOWLEDGEMENTS
|
318
|
-
|
319
|
-
### "POOR MAN"
|
320
|
-
|
321
|
-
I hope one day I will leave this Earth a poor man (like my code) owning only the most simple structure for the simple form of my existence. Thanks for having educated me in this wisdom goes to my former mentor [@trak3r](https://github.com/trak3r)!
|
322
|
-
|
323
|
-
|
324
|
-
|
325
383
|
|
326
384
|
# HOW THIS GEM IS TESTED
|
327
385
|
|
328
|
-
|
386
|
+
SETUP:
|
387
|
+
• Run bundle install
|
388
|
+
• if you can't get through see https://stackoverflow.com/questions/68050807/gem-install-mimemagic-v-0-3-10-fails-to-install-on-big-sur/68170982#68170982
|
329
389
|
|
330
|
-
We have two kinds of "sandboxes": a DUMMY sandbox, and also a STRAWMAN sandbox
|
331
390
|
|
332
391
|
The dummy sandbox is found at `spec/dummy`
|
333
392
|
|
334
|
-
The dummy lives as mostly checked- into the repository, except the folders where the generated code goes (`spec/dummy/app/views/`, `spec/dummy/app/controllers/`, `spec/dummy/specs/` are excluded from Git)
|
393
|
+
The dummy sandbox lives as mostly checked- into the repository, **except** the folders where the generated code goes (`spec/dummy/app/views/`, `spec/dummy/app/controllers/`, `spec/dummy/specs/` are excluded from Git)
|
335
394
|
|
336
395
|
When you run the **internal specs**, which you can do **at the root of this repo** using the command `rspec`, a set of specs will run to assert the generators are erroring when they are supposed to and producing code when they are supposed to.
|
337
396
|
|
338
|
-
|
339
397
|
The DUMMY testing DOES NOT test the actual functionality of the output code (it just tests the functionality of the generation process).
|
340
398
|
|
341
|
-
For this reason, I've also added something I call STRAWMAN testing, which is a set of steps that does these things:
|
342
|
-
|
343
|
-
The Strawman isn't in the repository, but if you build it locally, it will create itself into
|
344
|
-
|
345
|
-
`spec/strawman/`
|
346
|
-
|
347
|
-
1) Builds you a strawman sandbox app from scratch, using the native `rails new`
|
348
|
-
2) Makes a few small modifications to the new app to support this gem
|
349
|
-
3) Create two nonsense tables called OmnitableA and OmnitableB. Each omnitable has one of each kind of field (integer, text, string, date, time, etc)
|
350
|
-
4) In this way, it is a "Noah's Arc" testing strategy: It will build you a fully functional app using all of the feature sets of the gem.
|
351
|
-
5) The built app itself will contain its own specs
|
352
|
-
6) You will then cd into `spec/strawman` and run `rspec`. This second test suite now runs to full test all of the *generated* code.
|
353
|
-
|
354
|
-
|
data/db/schema.rb
CHANGED
@@ -27,7 +27,7 @@ ActiveRecord::Schema.define(version: 2021_03_06_225506) do
|
|
27
27
|
t.datetime "updated_at", precision: 6, null: false
|
28
28
|
end
|
29
29
|
|
30
|
-
create_table "
|
30
|
+
create_table "ghis", force: :cascade do |t|
|
31
31
|
t.integer "def_id"
|
32
32
|
t.datetime "created_at", precision: 6, null: false
|
33
33
|
t.datetime "updated_at", precision: 6, null: false
|
@@ -3,13 +3,31 @@ require 'ffaker'
|
|
3
3
|
|
4
4
|
|
5
5
|
module HotGlue
|
6
|
-
|
7
|
-
|
8
6
|
class Error < StandardError
|
9
7
|
end
|
10
8
|
|
11
|
-
|
12
9
|
module GeneratorHelper
|
10
|
+
def derrive_reference_name thing_as_string
|
11
|
+
assoc_class = eval(thing_as_string)
|
12
|
+
|
13
|
+
if assoc_class.respond_to?("name")
|
14
|
+
display_column = "name"
|
15
|
+
elsif assoc_class.respond_to?("to_label")
|
16
|
+
display_column = "to_label"
|
17
|
+
elsif assoc_class.respond_to?("full_name")
|
18
|
+
display_column = "full_name"
|
19
|
+
elsif assoc_class.respond_to?("display_name")
|
20
|
+
display_column = "display_name"
|
21
|
+
elsif assoc_class.respond_to?("email")
|
22
|
+
display_column = "email"
|
23
|
+
else
|
24
|
+
raise("this should have been caught by the checker in the initializer")
|
25
|
+
# puts "*** Oops: 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} 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)"
|
26
|
+
end
|
27
|
+
display_column
|
28
|
+
end
|
29
|
+
|
30
|
+
|
13
31
|
def text_area_output(col, field_length, col_identifier )
|
14
32
|
lines = field_length % 40
|
15
33
|
if lines > 5
|
@@ -55,12 +73,13 @@ module HotGlue
|
|
55
73
|
class_option :include, type: :string, default: ""
|
56
74
|
class_option :god, type: :boolean, default: false
|
57
75
|
class_option :gd, type: :boolean, default: false # alias for god
|
58
|
-
class_option :
|
76
|
+
class_option :specs_only, type: :boolean, default: false
|
59
77
|
class_option :no_specs, type: :boolean, default: false
|
60
78
|
class_option :no_delete, type: :boolean, default: false
|
61
79
|
class_option :no_create, type: :boolean, default: false
|
62
80
|
class_option :no_paginate, type: :boolean, default: false
|
63
81
|
class_option :big_edit, type: :boolean, default: false
|
82
|
+
class_option :show_only, type: :string, default: ""
|
64
83
|
|
65
84
|
def initialize(*meta_args) #:nodoc:
|
66
85
|
super
|
@@ -81,21 +100,32 @@ module HotGlue
|
|
81
100
|
@singular = args.first.tableize.singularize # should be in form hello_world
|
82
101
|
@plural = options['plural'] || @singular + "s" # supply to override; leave blank to use default
|
83
102
|
@auth = options['auth'] || "current_user"
|
84
|
-
@auth_identifier = options['
|
85
|
-
|
103
|
+
@auth_identifier = options['auth_identifier'] || (!@auth.nil? && @auth.gsub("current_", "")) || nil
|
104
|
+
|
105
|
+
|
106
|
+
@nest = (!options['nest'].empty? && options['nest']) || nil
|
86
107
|
@namespace = options['namespace'] || nil
|
108
|
+
|
87
109
|
@singular_class = @singular.titleize.gsub(" ", "")
|
88
110
|
@exclude_fields = []
|
89
111
|
@exclude_fields += options['exclude'].split(",").collect(&:to_sym)
|
90
112
|
|
91
|
-
if options['include']
|
113
|
+
if !options['include'].empty?
|
92
114
|
@include_fields = []
|
93
115
|
@include_fields += options['include'].split(",").collect(&:to_sym)
|
94
116
|
end
|
117
|
+
|
118
|
+
|
119
|
+
@show_only = []
|
120
|
+
if !options['show_only'].empty?
|
121
|
+
@show_only += options['show_only'].split(",").collect(&:to_sym)
|
122
|
+
end
|
123
|
+
|
95
124
|
auth_assoc = @auth.gsub("current_","")
|
96
125
|
|
97
126
|
@god = options['god'] || options['gd'] || false
|
98
127
|
@specs_only = options['specs_only'] || false
|
128
|
+
|
99
129
|
@no_specs = options['no_specs'] || false
|
100
130
|
@no_delete = options['no_delete'] || false
|
101
131
|
|
@@ -145,17 +175,29 @@ module HotGlue
|
|
145
175
|
|
146
176
|
if assoc
|
147
177
|
ownership_field = assoc.name.to_s + "_id"
|
178
|
+
elsif !@nest
|
179
|
+
exit_message = "*** Oops: It looks like is no association from current_#{@object_owner_sym} to a class called #{@singular_class}. If your user is called something else, pass with flag auth=current_X where X is the model for your users as lowercase. Also, be sure to implement current_X as a method on your controller. (If you really don't want to implement a current_X on your controller and want me to check some other method for your current user, see the section in the docs for auth_identifier.) To make a controller that can read all records, specify with --god."
|
180
|
+
|
148
181
|
else
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
182
|
+
if @god
|
183
|
+
|
184
|
+
exit_message= "*** Oops: god mode could not find the association(?). something is wrong."
|
185
|
+
else
|
186
|
+
@auth_check = "current_user"
|
187
|
+
@nested_args.each do |arg|
|
188
|
+
|
189
|
+
if !@auth_check.method("#{arg}s")
|
190
|
+
exit_message= "*** Oops: your nesting chain does not have a assocation for #{arg}s on #{@auth_check} something is wrong."
|
191
|
+
end
|
192
|
+
byebug
|
193
|
+
puts ""
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
154
197
|
raise(HotGlue::Error, exit_message)
|
155
198
|
end
|
156
199
|
end
|
157
200
|
|
158
|
-
|
159
201
|
if !@include_fields
|
160
202
|
@exclude_fields.push :id, :created_at, :updated_at, :encrypted_password,
|
161
203
|
:reset_password_token,
|
@@ -174,9 +216,11 @@ module HotGlue
|
|
174
216
|
|
175
217
|
end
|
176
218
|
|
177
|
-
|
178
|
-
|
179
219
|
@columns.each do |col|
|
220
|
+
if col.to_s.starts_with?("_")
|
221
|
+
@show_only << col
|
222
|
+
end
|
223
|
+
|
180
224
|
if object.columns_hash[col.to_s].type == :integer
|
181
225
|
if col.to_s.ends_with?("_id")
|
182
226
|
# guess the association name label
|
@@ -187,7 +231,7 @@ module HotGlue
|
|
187
231
|
begin
|
188
232
|
eval(assoc.class_name)
|
189
233
|
rescue NameError => e
|
190
|
-
exit_message = "*** Oops: The
|
234
|
+
exit_message = "*** Oops: The model #{singular_class} is missing an association for #{assoc_name} or the model doesn't exist. TODO: Please implement a model for #{assoc_name.titlecase}; your model #{singular_class.titlecase} should have_many :#{assoc_name}s. To make a controller that can read all records, specify with --god."
|
191
235
|
raise(HotGlue::Error, exit_message)
|
192
236
|
|
193
237
|
end
|
@@ -199,18 +243,16 @@ module HotGlue
|
|
199
243
|
end
|
200
244
|
|
201
245
|
assoc_class = eval(assoc.class_name)
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
#
|
210
|
-
elsif assoc_class.column_names.include?("email")
|
211
|
-
# display_column = "email"
|
246
|
+
|
247
|
+
name_list = [:name, :to_label, :full_name, :display_name, :email]
|
248
|
+
|
249
|
+
|
250
|
+
if name_list.collect{ |field|
|
251
|
+
assoc_class.column_names.include?(field.to_s) || assoc_class.instance_methods.include?(field)
|
252
|
+
}.any?
|
253
|
+
# do nothing here
|
212
254
|
else
|
213
|
-
exit_message= "*** Oops: 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} 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)"
|
255
|
+
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)"
|
214
256
|
raise(HotGlue::Error,exit_message)
|
215
257
|
end
|
216
258
|
end
|
@@ -234,15 +276,18 @@ module HotGlue
|
|
234
276
|
|
235
277
|
unless @specs_only
|
236
278
|
template "controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "#{plural}_controller.rb")
|
237
|
-
if @namespace
|
238
|
-
|
279
|
+
if @namespace
|
280
|
+
begin
|
281
|
+
eval(controller_descends_from)
|
282
|
+
puts " skipping base controller #{controller_descends_from}"
|
283
|
+
rescue NameError => e
|
284
|
+
template "base_controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "base_controller.rb")
|
285
|
+
end
|
239
286
|
end
|
240
287
|
end
|
241
288
|
|
242
289
|
unless @no_specs
|
243
|
-
template "
|
244
|
-
template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_spec.rb")
|
245
|
-
|
290
|
+
template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
|
246
291
|
end
|
247
292
|
|
248
293
|
template "_errors.haml", File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", "_errors.haml")
|
@@ -321,9 +366,9 @@ module HotGlue
|
|
321
366
|
end
|
322
367
|
|
323
368
|
|
324
|
-
def path_helper_full
|
325
|
-
|
326
|
-
end
|
369
|
+
# def path_helper_full
|
370
|
+
# "#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{singular}_path"
|
371
|
+
# end
|
327
372
|
|
328
373
|
def path_helper_args
|
329
374
|
if @nested_args.any?
|
@@ -435,6 +480,9 @@ module HotGlue
|
|
435
480
|
end
|
436
481
|
|
437
482
|
|
483
|
+
|
484
|
+
|
485
|
+
|
438
486
|
def copy_view_files
|
439
487
|
return if @specs_only
|
440
488
|
haml_views.each do |view|
|
@@ -504,6 +552,16 @@ module HotGlue
|
|
504
552
|
col_spaces_prepend = " "
|
505
553
|
|
506
554
|
res = @columns.map { |col|
|
555
|
+
|
556
|
+
if @show_only.include?(col)
|
557
|
+
|
558
|
+
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{col.to_s})}\"}
|
559
|
+
= @#{singular}.#{col.to_s}
|
560
|
+
%label.form-text
|
561
|
+
#{col.to_s.humanize}\n"
|
562
|
+
else
|
563
|
+
|
564
|
+
|
507
565
|
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
508
566
|
limit = eval("#{singular_class}.columns_hash['#{col}']").limit
|
509
567
|
sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
|
@@ -512,36 +570,17 @@ module HotGlue
|
|
512
570
|
when :integer
|
513
571
|
# look for a belongs_to on this object
|
514
572
|
if col.to_s.ends_with?("_id")
|
515
|
-
|
516
|
-
#
|
517
|
-
|
518
|
-
|
519
|
-
|
520
|
-
# if assoc.nil?
|
521
|
-
# exit_message= "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
522
|
-
# exit
|
523
|
-
# end
|
524
|
-
|
525
|
-
|
526
|
-
assoc_class = eval(assoc.class_name)
|
527
|
-
|
528
|
-
if assoc_class.column_names.include?("name")
|
529
|
-
display_column = "name"
|
530
|
-
elsif assoc_class.column_names.include?("to_label")
|
531
|
-
display_column = "to_label"
|
532
|
-
elsif assoc_class.column_names.include?("full_name")
|
533
|
-
display_column = "full_name"
|
534
|
-
elsif assoc_class.column_names.include?("display_name")
|
535
|
-
display_column = "display_name"
|
536
|
-
elsif assoc_class.column_names.include?("email")
|
537
|
-
display_column = "email"
|
538
|
-
else
|
539
|
-
raise("this should have been caught by the checker in the initializer")
|
540
|
-
# puts "*** Oops: 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} 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)"
|
573
|
+
assoc_name = col.to_s.gsub("_id","")
|
574
|
+
assoc = eval("#{singular_class}.reflect_on_association(:#{assoc_name})")
|
575
|
+
if assoc.nil?
|
576
|
+
exit_message= "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
577
|
+
exit
|
541
578
|
end
|
579
|
+
display_column = derrive_reference_name(assoc.class_name)
|
580
|
+
|
542
581
|
|
543
582
|
"#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{assoc_name.to_s})}\"}
|
544
|
-
#{col_spaces_prepend}= f.collection_select(:#{col.to_s}, #{
|
583
|
+
#{col_spaces_prepend}= f.collection_select(:#{col.to_s}, #{assoc.class_name}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col.to_s} }, class: 'form-control')
|
545
584
|
#{col_spaces_prepend}%label.small.form-text.text-muted
|
546
585
|
#{col_spaces_prepend} #{col.to_s.humanize}"
|
547
586
|
|
@@ -591,7 +630,7 @@ module HotGlue
|
|
591
630
|
#{col_spaces_prepend}= f.label(:#{col.to_s}, value: 'Yes', for: '#{singular}_#{col.to_s}_1')
|
592
631
|
"
|
593
632
|
end
|
594
|
-
|
633
|
+
end
|
595
634
|
}.join("\n")
|
596
635
|
return res
|
597
636
|
end
|
@@ -621,25 +660,9 @@ module HotGlue
|
|
621
660
|
exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
|
622
661
|
raise(HotGlue::Error,exit_message)
|
623
662
|
end
|
624
|
-
|
625
|
-
assoc_class = eval(assoc.class_name)
|
626
663
|
|
627
|
-
|
628
|
-
display_column = "name"
|
629
|
-
elsif assoc_class.column_names.include?("to_label")
|
630
|
-
display_column = "to_label"
|
631
|
-
elsif assoc_class.column_names.include?("full_name")
|
632
|
-
display_column = "full_name"
|
633
|
-
elsif assoc_class.column_names.include?("display_name")
|
634
|
-
display_column = "display_name"
|
635
|
-
elsif assoc_class.column_names.include?("email")
|
636
|
-
display_column = "email"
|
637
|
-
elsif assoc_class.column_names.include?("number")
|
638
|
-
display_column = "number"
|
664
|
+
display_column = derrive_reference_name(assoc.class_name)
|
639
665
|
|
640
|
-
else
|
641
|
-
puts "*** Oops: 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, 5) email, or 6) number directly on your #{assoc.class_name} 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)"
|
642
|
-
end
|
643
666
|
|
644
667
|
"#{col_identifer}
|
645
668
|
= #{singular}.#{assoc.name.to_s}.try(:#{display_column}) || '<span class=\"content alert-danger\">MISSING</span>'.html_safe"
|
@@ -713,19 +736,20 @@ module HotGlue
|
|
713
736
|
me = eval(singular_class)
|
714
737
|
|
715
738
|
@display_class ||=
|
716
|
-
if me.
|
739
|
+
if me.column_names.include?("name") || me.instance_methods(false).include?(:name)
|
740
|
+
# note that all class object respond_to?(:name) with the name of their own class
|
741
|
+
# this one is unique
|
717
742
|
"name"
|
718
|
-
elsif me.
|
743
|
+
elsif me.column_names.include?("to_label") || me.instance_methods(false).include?(:to_label)
|
719
744
|
"to_label"
|
720
|
-
elsif me.
|
745
|
+
elsif me.column_names.include?("full_name") || me.instance_methods(false).include?(:full_name)
|
721
746
|
"full_name"
|
722
|
-
elsif me.
|
747
|
+
elsif me.column_names.include?("display_name") || me.instance_methods(false).include?(:display_name)
|
723
748
|
"display_name"
|
724
|
-
elsif me.
|
749
|
+
elsif me.column_names.include?("email") || me.instance_methods(false).include?(:email)
|
725
750
|
"email"
|
726
|
-
elsif me.
|
727
|
-
|
728
|
-
|
751
|
+
elsif me.column_names.include?("number") || me.instance_methods(false).include?(:number)
|
752
|
+
"number"
|
729
753
|
else
|
730
754
|
exit_message = "*** Oops: Can't find any column to use as the display label on #{singular_class} model . TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name, 5) email, or 6) number directly on your #{singular_class} 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)"
|
731
755
|
raise(HotGlue::Error, exit_message)
|
@@ -753,7 +777,8 @@ module HotGlue
|
|
753
777
|
|
754
778
|
|
755
779
|
def paginate
|
756
|
-
"
|
780
|
+
"- if #{plural}.respond_to?(:total_pages)
|
781
|
+
= paginate #{plural}"
|
757
782
|
end
|
758
783
|
|
759
784
|
private # thor does something fancy like sending the class all of its own methods during some strange run sequence
|
@@ -5,6 +5,3 @@
|
|
5
5
|
= form_with model: <%= singular %>, url: <%= path_helper_plural %>(<%= nested_objects_arity %>), method: "post" do |f|
|
6
6
|
= render partial: "<%=namespace_with_slash%><%= @plural %>/form", locals: {<%= singular %>: <%= singular %>, f: f}
|
7
7
|
|
8
|
-
.row
|
9
|
-
.col-md-12
|
10
|
-
= f.submit "Save", class: "btn btn-primary pull-right"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
<%= all_line_fields %>
|
2
2
|
.col
|
3
3
|
<% if destroy_action %>
|
4
|
-
= link_to "Delete <i class='fa fa-1x fa-remove'></i>".html_safe, <%=
|
4
|
+
= link_to "Delete <i class='fa fa-1x fa-remove'></i>".html_safe, <%= path_helper_singular %>(<%= path_helper_args %>), method: :delete, data: {confirm: 'Are you sure?'}, disable_with: "Loading...", class: "delete-<%= singular %>-button btn btn-primary "
|
5
5
|
<% end %>
|
6
6
|
|
7
|
-
= link_to "Edit <i class='fa fa-1x fa-list-alt'></i>".html_safe, edit_<%=
|
7
|
+
= link_to "Edit <i class='fa fa-1x fa-list-alt'></i>".html_safe, edit_<%= path_helper_singular %>(<%= path_helper_args %>), <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary "
|
@@ -1,7 +1,6 @@
|
|
1
1
|
class <%= controller_class_name %> < <%= controller_descends_from %>
|
2
2
|
<% unless @auth_identifier == '' || @auth.nil? %>before_action :authenticate_<%= @auth_identifier %>!<% end %>
|
3
|
-
|
4
|
-
before_action :load_<%= arg %><% end %> <% end %>
|
3
|
+
|
5
4
|
before_action :load_<%= singular_name %>, only: [:show, :edit, :update, :destroy]
|
6
5
|
helper :hot_glue
|
7
6
|
include HotGlue::ControllerHelper
|
@@ -11,22 +10,23 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
11
10
|
<% end %>
|
12
11
|
|
13
12
|
<% if any_nested? %><% nest_chain = [] %> <% @nested_args.each { |arg|
|
14
|
-
this_scope = nest_chain.empty? ? "#{@auth ? auth_object : class_name}.#{arg}s" : "
|
15
|
-
nest_chain << arg %>
|
16
|
-
|
13
|
+
this_scope = nest_chain.empty? ? "#{@auth ? auth_object : class_name}.#{arg}s" : "#{nest_chain.last}.#{arg}s"
|
14
|
+
nest_chain << arg %>
|
15
|
+
def <%= arg %>
|
16
|
+
@<%= arg %> ||= <%= this_scope %>.find(params[:<%= arg %>_id])
|
17
17
|
end<% } %><% end %>
|
18
18
|
|
19
19
|
<% if !@self_auth %>
|
20
20
|
def load_<%= singular_name %>
|
21
|
-
@<%= singular_name %> = <%= object_scope %>.find(params[:id])
|
21
|
+
@<%= singular_name %> = <%= object_scope.gsub("@",'') %>.find(params[:id])
|
22
22
|
end
|
23
23
|
<% else %>
|
24
24
|
def load_<%= singular_name %>
|
25
|
-
@<%= singular_name %> = <%= auth_object %>
|
25
|
+
@<%= singular_name %> = <%= auth_object.gsub("@",'') %>
|
26
26
|
end<% end %>
|
27
27
|
|
28
28
|
def load_all_<%= plural %>
|
29
|
-
<% if !@self_auth %>@<%= plural_name %> = <%= object_scope %><% if model_has_strings? %>.where(<%=class_name %>.arel_table[:email].matches("%#{@__general_string}%"))<% end %>.page(params[:page])
|
29
|
+
<% if !@self_auth %>@<%= plural_name %> = <%= object_scope.gsub("@",'') %><% if model_has_strings? %>.where(<%=class_name %>.arel_table[:email].matches("%#{@__general_string}%"))<% end %>.page(params[:page])
|
30
30
|
<% else %>@<%= plural_name %> = [<%= auth_object %>]<% end %>
|
31
31
|
end
|
32
32
|
|
@@ -81,8 +81,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
81
81
|
end
|
82
82
|
|
83
83
|
def update
|
84
|
-
if
|
85
|
-
|
84
|
+
if @<%= singular_name %>.update(modify_date_inputs_on_params(<%= singular %>_params<%= @auth ? ', ' + @auth : '' %>))
|
85
|
+
flash[:notice] = "Saved #{@<%= singular %>.<%= display_class %>}"
|
86
|
+
else
|
87
|
+
flash[:alert] = "<%= singular_name.titlecase %> could not be saved."
|
86
88
|
end
|
87
89
|
respond_to do |format|
|
88
90
|
format.turbo_stream
|
@@ -1,108 +1,147 @@
|
|
1
1
|
require 'rails_helper'
|
2
2
|
|
3
3
|
describe "interaction for <%= controller_class_name %>", type: :feature do
|
4
|
-
|
5
|
-
let(:<%=
|
4
|
+
include HotGlue::ControllerHelper
|
5
|
+
<% unless @auth.nil? %>let(:<%= @auth %>) {create(:<%= @auth.gsub('current_', '') %>)}<%end%>
|
6
6
|
|
7
|
-
|
7
|
+
let!(:<%= singular %>1) {create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> )}
|
8
|
+
let!(:<%= singular %>2) {create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> )}
|
9
|
+
let!(:<%= singular %>3) {create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> )}
|
8
10
|
|
9
|
-
|
10
|
-
@request.env["devise.mapping"] = Devise.mappings[:account]
|
11
|
+
<%= objest_nest_factory_setup %>
|
11
12
|
|
12
|
-
|
13
|
+
before(:each) do
|
14
|
+
login_as(<%= @auth %>)
|
13
15
|
end
|
14
16
|
|
15
17
|
describe "index" do
|
16
|
-
it "should
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
it "should show me the list" do
|
19
|
+
visit <%= path_helper_plural %>
|
20
|
+
|
21
|
+
<%=
|
22
|
+
@columns.map { |col|
|
23
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
24
|
+
# limit = eval("#{singular_class}.columns_hash['#{col}']").limit
|
25
|
+
# sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
|
26
|
+
#
|
27
|
+
|
28
|
+
case type
|
29
|
+
when :datetime
|
30
|
+
" " + ["expect(page).to have_content(#{singular}#{rand(3)+1}.#{col}.in_time_zone(#{ @auth }.timezone).strftime('%m/%d/%Y @ %l:%M %p ').gsub(' ', ' ') + timezonize(#{ @auth }.timezone) )"].join("\n ")
|
31
|
+
|
32
|
+
else
|
33
|
+
" " + ["expect(page).to have_content(#{singular}#{rand(3)+1}.#{col})"].join("\n ")
|
34
|
+
|
21
35
|
end
|
22
36
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
}
|
37
|
+
}.join("\n")
|
38
|
+
|
39
|
+
%>
|
40
|
+
|
28
41
|
end
|
29
42
|
end
|
30
43
|
|
31
|
-
describe "create" do
|
32
|
-
it "should create a new <%= singular %>" do
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
<%= singular %>: {
|
37
|
-
<%= columns_spec_with_sample_data %>
|
38
|
-
}}
|
39
|
-
}.to change { <%= @singular_class %>.all.count }.by(1)
|
40
|
-
assert_response :ok
|
41
|
-
end
|
44
|
+
describe "new & create" do
|
45
|
+
it "should create a new <%= singular.titlecase %>" do
|
46
|
+
visit <%= path_helper_plural %>
|
47
|
+
click_link "New <%= singular.titlecase %>"
|
48
|
+
expect(page).to have_selector(:xpath, './/h3[contains(., "New <%= singular.titlecase %>")]')
|
42
49
|
|
43
|
-
|
44
|
-
|
45
|
-
|
50
|
+
<%=
|
51
|
+
@columns.map { |col|
|
52
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
53
|
+
# limit = eval("#{singular_class}.columns_hash['#{col}']").limit
|
54
|
+
# sql_type = eval("#{singular_class}.columns_hash['#{col}']").sql_type
|
46
55
|
#
|
47
|
-
# expect(controller).to set_flash.now[:alert].to(/Oops, your <%= singular %> could not be saved/)
|
48
|
-
# end
|
49
|
-
end
|
50
56
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
}
|
57
|
-
|
57
|
+
case type
|
58
|
+
when :datetime
|
59
|
+
when :integer
|
60
|
+
" " + 'find("input#' + singular + '_' + col.to_s + '").fill_in(with: rand(10))'
|
61
|
+
else
|
62
|
+
" " + "new_#{col} = 'new_test-email@nowhere.com' \n" +
|
63
|
+
' ' + 'find("input#' + singular + '_' + col.to_s + '").fill_in(with: new_' + col.to_s + ')'
|
64
|
+
end
|
65
|
+
|
66
|
+
}.join("\n")
|
67
|
+
|
68
|
+
%>
|
69
|
+
click_button "Save"
|
70
|
+
expect(page).to have_content("Successfully created")
|
71
|
+
|
72
|
+
<%=
|
73
|
+
@columns.map { |col|
|
74
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
75
|
+
|
76
|
+
case type
|
77
|
+
when :datetime
|
78
|
+
when :integer
|
79
|
+
else
|
80
|
+
"expect(page).to have_content(new_#{col})"
|
81
|
+
end
|
82
|
+
|
83
|
+
}.join("\n")
|
84
|
+
%>
|
85
|
+
|
58
86
|
end
|
59
87
|
end
|
60
88
|
|
61
89
|
describe "show" do
|
62
90
|
it "should return a view form" do
|
63
|
-
|
64
|
-
|
65
|
-
id: <%= singular %>.id
|
66
|
-
}
|
67
|
-
assert_response :ok
|
91
|
+
visit <%= path_helper_plural %>
|
92
|
+
|
68
93
|
end
|
69
94
|
end
|
70
95
|
|
71
|
-
describe "update" do
|
72
|
-
it "should
|
73
|
-
|
74
|
-
|
75
|
-
<%= (@nested_args.empty? ? "" : objest_nest_params_by_id_for_specs + ",") %>
|
76
|
-
id: <%= singular %>.id,
|
77
|
-
<%= singular %>: {
|
78
|
-
<%= columns_spec_with_sample_data %>
|
79
|
-
}}
|
80
|
-
|
81
|
-
assert_response :ok
|
82
|
-
end
|
96
|
+
describe "edit & update" do
|
97
|
+
it "should return an editable form" do
|
98
|
+
visit <%= path_helper_plural %>
|
99
|
+
find("a.edit-<%= singular %>-button[href='/<%= namespace_with_slash %><%= plural %>/#{<%= singular %>1.id}/edit']").click
|
83
100
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
101
|
+
expect(page).to have_content("Editing #{<%= singular %>1.<%= derrive_reference_name(singular_class) %>}")
|
102
|
+
<%=
|
103
|
+
@columns.map { |col|
|
104
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
105
|
+
|
106
|
+
case type
|
107
|
+
when :datetime
|
108
|
+
when :integer
|
109
|
+
else
|
110
|
+
" " + "new_#{col.to_s} = Faker::Name.new \n" +
|
111
|
+
|
112
|
+
' find("input[name=\'' + singular + '[' + col.to_s + ']\'").fill_in(with: new_' + col.to_s + ')'
|
113
|
+
|
114
|
+
end
|
115
|
+
}.join("\n")
|
116
|
+
%>
|
117
|
+
click_button "Save"
|
118
|
+
within("turbo-frame#<%= singular %>__#{<%= singular %>1.id} ") do
|
119
|
+
|
120
|
+
|
121
|
+
<%=
|
122
|
+
@columns.map { |col|
|
123
|
+
type = eval("#{singular_class}.columns_hash['#{col}']").type
|
124
|
+
case type
|
125
|
+
when :datetime
|
126
|
+
when :integer
|
127
|
+
else
|
128
|
+
' expect(page).to have_content(new_' + col.to_s + ')'
|
129
|
+
end
|
130
|
+
}.join("\n")
|
131
|
+
%>
|
132
|
+
|
133
|
+
end
|
134
|
+
end
|
96
135
|
end
|
97
136
|
|
98
|
-
describe "
|
137
|
+
describe "destroy" do
|
99
138
|
it "should destroy" do
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
expect(<%=
|
139
|
+
visit <%= path_helper_plural %>
|
140
|
+
accept_alert do
|
141
|
+
find("a.delete-<%= singular %>-button[href='<%= namespace_with_dash %>/<%= plural %>/#{<%= singular %>1.id}']").click
|
142
|
+
end
|
143
|
+
expect(page).to_not have_content(<%= singular %>1.email)
|
144
|
+
expect(<%= singular_class %>.where(id: <%= singular %>1.id).count).to eq(0)
|
106
145
|
end
|
107
146
|
end
|
108
147
|
end
|
@@ -3,3 +3,7 @@
|
|
3
3
|
= render partial: 'line', locals: {<%= singular %>: @<%= singular %> <%= nested_assignments_with_leading_comma %> }
|
4
4
|
|
5
5
|
|
6
|
+
= turbo_stream.replace "flash_notices" do
|
7
|
+
= render partial: "layouts/flash_notices"
|
8
|
+
- if @<%= singular %>.errors.any?
|
9
|
+
= render partial: "errors", locals: {resource: @<%= singular %>}
|
data/lib/hotglue/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hot-glue
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.1.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: 2021-
|
11
|
+
date: 2021-06-28 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -115,7 +115,7 @@ files:
|
|
115
115
|
- config/database.yml
|
116
116
|
- db/migrate/20210306212711_create_abcs.rb
|
117
117
|
- db/migrate/20210306223300_create_defs.rb
|
118
|
-
- db/migrate/
|
118
|
+
- db/migrate/20210306223305_create_ghis.rb
|
119
119
|
- db/migrate/20210306223309_create_jkls.rb
|
120
120
|
- db/migrate/20210306223701_devise_create_users.rb
|
121
121
|
- db/migrate/20210306225506_create_xyzs.rb
|
@@ -138,7 +138,6 @@ files:
|
|
138
138
|
- lib/generators/hot_glue/templates/edit.turbo_stream.haml
|
139
139
|
- lib/generators/hot_glue/templates/index.haml
|
140
140
|
- lib/generators/hot_glue/templates/new.haml
|
141
|
-
- lib/generators/hot_glue/templates/request_spec.rb.erb
|
142
141
|
- lib/generators/hot_glue/templates/system_spec.rb.erb
|
143
142
|
- lib/generators/hot_glue/templates/update.turbo_stream.haml
|
144
143
|
- lib/hot-glue.rb
|
@@ -149,8 +148,8 @@ licenses:
|
|
149
148
|
- Nonstandard
|
150
149
|
metadata:
|
151
150
|
source_code_uri: https://github.com/jasonfb/hot-glue
|
152
|
-
documentation_uri: https://
|
153
|
-
homepage_uri: https://
|
151
|
+
documentation_uri: https://www.instagram.com/jfbcodes/
|
152
|
+
homepage_uri: https://jasonfleetwoodboldt.com/hot-glue/
|
154
153
|
post_install_message: |
|
155
154
|
---------------------------------------------
|
156
155
|
Welcome to Hot Glue - A Scaffold Building Companion for Hotwire + Turbo-Rails
|
@@ -159,11 +158,11 @@ post_install_message: |
|
|
159
158
|
|
160
159
|
* Build plug-and-play scaffolding mixing HAML with the power of Hotwire and Turbo-Rails
|
161
160
|
* Automatically Reads Your Models (make them before building your scaffolding!)
|
162
|
-
* Excellent for CRUD, lists with pagination
|
163
|
-
* Great for prototyping
|
164
|
-
* Plays nicely with Devise, Kaminari, Haml-Rails, Rspec
|
165
|
-
* Create specs automatically along with the controllers.
|
166
|
-
* Nest your routes model-by-model for built-in poor man's authentication
|
161
|
+
* Excellent for CRUD, lists with pagination (coming soon: searching & sorting)
|
162
|
+
* Great for prototyping.
|
163
|
+
* Plays nicely with Devise, Kaminari, Haml-Rails, Rspec, FontAwesome
|
164
|
+
* Create specs automatically along with the generated controllers.
|
165
|
+
* Nest your routes model-by-model for built-in poor man's authentication.
|
167
166
|
* Throw the scaffolding away when your app is ready to graduate to its next phase.
|
168
167
|
|
169
168
|
see README for complete instructions.
|
@@ -182,7 +181,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
182
181
|
- !ruby/object:Gem::Version
|
183
182
|
version: '0'
|
184
183
|
requirements: []
|
185
|
-
rubygems_version: 3.
|
184
|
+
rubygems_version: 3.0.9
|
186
185
|
signing_key:
|
187
186
|
specification_version: 4
|
188
187
|
summary: A gem build scaffolding.
|
@@ -1,110 +0,0 @@
|
|
1
|
-
require 'rails_helper'
|
2
|
-
|
3
|
-
describe <%= controller_class_name %> do
|
4
|
-
render_views
|
5
|
-
<% unless @auth.nil? %> let(:<%= @auth %>) {create(:<%= @auth.gsub('current_', '') %>)}<%end%>
|
6
|
-
let(:<%= singular %>) {create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> )}
|
7
|
-
|
8
|
-
<%= objest_nest_factory_setup %>
|
9
|
-
|
10
|
-
before(:each) do
|
11
|
-
@request.env["devise.mapping"] = Devise.mappings[:account]
|
12
|
-
|
13
|
-
sign_in <%= @auth %>, scope: :<%= @auth %>
|
14
|
-
end
|
15
|
-
|
16
|
-
describe "index" do
|
17
|
-
it "should respond" do
|
18
|
-
get :index, xhr: true, format: 'js', params: {
|
19
|
-
<%= objest_nest_params_by_id_for_specs %>
|
20
|
-
}
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
describe "new" do
|
25
|
-
it "should show form" do
|
26
|
-
get :new, xhr: true, format: 'js', params: {
|
27
|
-
<%= objest_nest_params_by_id_for_specs %>
|
28
|
-
}
|
29
|
-
end
|
30
|
-
end
|
31
|
-
|
32
|
-
describe "create" do
|
33
|
-
it "should create a new <%= singular %>" do
|
34
|
-
expect {
|
35
|
-
post :create, xhr: true, format: 'js', params: {
|
36
|
-
<%= (@nested_args.empty? ? "" : objest_nest_params_by_id_for_specs + ",") %>
|
37
|
-
<%= singular %>: {
|
38
|
-
<%= columns_spec_with_sample_data %>
|
39
|
-
}}
|
40
|
-
}.to change { <%= @singular_class %>.all.count }.by(1)
|
41
|
-
assert_response :ok
|
42
|
-
end
|
43
|
-
|
44
|
-
# it "should not create if there are errors" do
|
45
|
-
# post :create, xhr: true, format: 'js', params: {id: <%= singular %>.id,
|
46
|
-
# <%= singular %>: {skin_id: nil}}
|
47
|
-
#
|
48
|
-
# expect(controller).to set_flash.now[:alert].to(/Oops, your <%= singular %> could not be saved/)
|
49
|
-
# end
|
50
|
-
end
|
51
|
-
|
52
|
-
describe "edit" do
|
53
|
-
it "should return an editable form" do
|
54
|
-
get :edit, xhr: true, format: 'js', params: {
|
55
|
-
<%= (@nested_args.empty? ? "" : objest_nest_params_by_id_for_specs + ",") %>
|
56
|
-
id: <%= singular %>.id
|
57
|
-
}
|
58
|
-
assert_response :ok
|
59
|
-
end
|
60
|
-
end
|
61
|
-
|
62
|
-
describe "show" do
|
63
|
-
it "should return a view form" do
|
64
|
-
get :show, xhr: true, format: 'js', params: {
|
65
|
-
<%= (@nested_args.empty? ? "" : objest_nest_params_by_id_for_specs + ",") %>
|
66
|
-
id: <%= singular %>.id
|
67
|
-
}
|
68
|
-
assert_response :ok
|
69
|
-
end
|
70
|
-
end
|
71
|
-
|
72
|
-
describe "update" do
|
73
|
-
it "should update" do
|
74
|
-
put :update, xhr: true, format: 'js',
|
75
|
-
params: {
|
76
|
-
<%= (@nested_args.empty? ? "" : objest_nest_params_by_id_for_specs + ",") %>
|
77
|
-
id: <%= singular %>.id,
|
78
|
-
<%= singular %>: {
|
79
|
-
<%= columns_spec_with_sample_data %>
|
80
|
-
}}
|
81
|
-
|
82
|
-
assert_response :ok
|
83
|
-
end
|
84
|
-
|
85
|
-
# it "should not update if invalid" do
|
86
|
-
# put :update, xhr: true, format: 'js',
|
87
|
-
# params: {
|
88
|
-
# id: <%= singular %>.id,
|
89
|
-
# <%= singular %>: {
|
90
|
-
# <%= columns_spec_with_sample_data %>
|
91
|
-
# }}
|
92
|
-
#
|
93
|
-
# assert_response :ok
|
94
|
-
#
|
95
|
-
# expect(controller).to set_flash.now[:alert].to(/Oops, your <%= singular %> could not be saved/)
|
96
|
-
# end
|
97
|
-
end
|
98
|
-
|
99
|
-
describe "#destroy" do
|
100
|
-
it "should destroy" do
|
101
|
-
post :destroy, format: 'js', params: {
|
102
|
-
<%= (@nested_args.empty? ? "" : objest_nest_params_by_id_for_specs + ",") %>
|
103
|
-
id: <%= singular %>.id
|
104
|
-
}
|
105
|
-
assert_response :ok
|
106
|
-
expect(<%= @singular_class %>.count).to be(0)
|
107
|
-
end
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|