hot-glue 0.4.2 → 0.4.6
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 +2 -1
- data/Gemfile.lock +3 -3
- data/{LICENCE → LICENSE} +10 -6
- data/README.md +851 -0
- data/lib/generators/hot_glue/helpers.rb +13 -0
- data/lib/generators/hot_glue/install_generator.rb +45 -14
- data/lib/generators/hot_glue/layout/builder.rb +11 -9
- data/lib/generators/hot_glue/markup_templates/erb.rb +4 -6
- data/lib/generators/hot_glue/scaffold_generator.rb +85 -34
- data/lib/generators/hot_glue/templates/erb/_list.erb +22 -19
- data/lib/generators/hot_glue/templates/erb/_new_form.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/_show.erb +3 -3
- data/lib/hotglue/version.rb +1 -1
- metadata +7 -16
data/README.md
CHANGED
@@ -1,3 +1,854 @@
|
|
1
|
+
|
2
|
+
[![Build Status](https://app.travis-ci.com/jasonfb/hot-glue.svg?branch=main)](https://travis-ci.com/jasonfb/hot-glue)
|
3
|
+
|
4
|
+
|
5
|
+
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)).
|
6
|
+
|
7
|
+
|
8
|
+
Using Turbo-Rails and Hotwire (default in Rails 7) you get a lightning-fast out-of-the-box CRUD building experience.
|
9
|
+
|
10
|
+
Every page displays only a list view: new and edit operations happen as 'edit-in-place', so the user never leaves the page.
|
11
|
+
|
12
|
+
Because all page navigation is Turbo's responsibilty, everything plugs & plays nicely into a Turbo-backed Rails app.
|
13
|
+
|
14
|
+
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.
|
15
|
+
|
16
|
+
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.
|
17
|
+
|
18
|
+
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.
|
19
|
+
|
20
|
+
Hot Glue generates functionality that's quick and dirty. It lets you be crafty. As with a real hot glue gun, use with caution.
|
21
|
+
|
22
|
+
* Build plug-and-play scaffolding mixing generated ERB or HAML with the power of Hotwire and Turbo-Rails
|
23
|
+
* Everything edits-in-place (unless you use --big-edit, then it won't)
|
24
|
+
* Automatically Reads Your Models (make them before building your scaffolding!)
|
25
|
+
* Excellent for CREATE-READ-UPDATE-DELETE (CRUD), lists with pagination (coming soon: searching & sorting)
|
26
|
+
* Great for prototyping, but you should learn Rails fundamentals first.
|
27
|
+
* 'Packaged' with Devise, Kaminari, Rspec, FontAwesome
|
28
|
+
* Create system specs automatically along with the generated code.
|
29
|
+
* Nest your routes model-by-model for built-in poor man's authentication.
|
30
|
+
* Throw the scaffolding away when your app is ready to graduate to its next phase.
|
31
|
+
|
32
|
+
# Hot Glue Tutorial
|
33
|
+
## [GET THE COURSE TODAY (includes Hot Glue License)](https://jfb.teachable.com/courses/hot-glue-in-depth-tutorial/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) **only $60 USD!**
|
34
|
+
|
35
|
+
| | |
|
36
|
+
| ------------- | ------------- |
|
37
|
+
| ![Teachable-225x225](https://user-images.githubusercontent.com/59002/147857335-a919e095-e6de-4718-8513-736d1f283a0b.png) | Now avaiale on [Teachable](https://jfb.teachable.com/courses/hot-glue-in-depth-tutorial/?utm_source=github.com&utm_campaign=github_hot_glue_readme_page) |
|
38
|
+
|
39
|
+
|
40
|
+
|
41
|
+
|
42
|
+
|
43
|
+
## HOW EASY?
|
44
|
+
|
45
|
+
```
|
46
|
+
rails generate hot_glue:scaffold Thing
|
47
|
+
```
|
48
|
+
|
49
|
+
Generate a quick scaffold to manage a table called `pronouns`
|
50
|
+
![hot-glue-3](https://user-images.githubusercontent.com/59002/116405509-bdee2f00-a7fd-11eb-9723-4c6e22f81bd3.gif)
|
51
|
+
|
52
|
+
Instantly get a simple CRUD interface
|
53
|
+
|
54
|
+
![hot-glue-4](https://user-images.githubusercontent.com/59002/116405517-c2b2e300-a7fd-11eb-8423-d43e3afc9fa6.gif)
|
55
|
+
|
56
|
+
# Getting Started
|
57
|
+
|
58
|
+
_If you are on Rails 6, skip to section Rails 6 Setup and complete those steps FIRST._
|
59
|
+
|
60
|
+
|
61
|
+
## 1. ADD RSPEC, FACTORY-BOT, AND FFAKER
|
62
|
+
|
63
|
+
add these 3 gems to your gemfile **inside a group for both :development and :test*. Do not add these gems to only the :test group or else your will have problems with the generators.
|
64
|
+
```
|
65
|
+
gem 'rspec-rails'
|
66
|
+
gem 'factory_bot_rails'
|
67
|
+
gem 'ffaker'
|
68
|
+
```
|
69
|
+
|
70
|
+
- run `rails generate rspec:install`
|
71
|
+
|
72
|
+
- replace `application.css` with a new file (delete old contents) `application.scss`
|
73
|
+
|
74
|
+
THIS FILE CAN BE EMPTY, BUT WILL BE USED BY THEME INSTALLER
|
75
|
+
|
76
|
+
## 2. ADD BOOTSTRAP (OPTIONAL)
|
77
|
+
|
78
|
+
_BOOTSTRAP IS NO LONGER NEEDED_, but I recommend it.
|
79
|
+
|
80
|
+
IF you are using `--layout=bootstrap` (step 3), you must install Bootstrap here.
|
81
|
+
|
82
|
+
Bootstrap with Webpacker is no longer in Rails 7 by default. (For that see ________TBD________)
|
83
|
+
|
84
|
+
For Bootstrap with Sprockets (recommended by Rails team), see https://github.com/twbs/bootstrap-rubygem
|
85
|
+
|
86
|
+
If going the the Bootstrap with Sprockets route, note the gem is
|
87
|
+
```
|
88
|
+
gem 'bootstrap', '~> 5.1.3'
|
89
|
+
```
|
90
|
+
|
91
|
+
Then, all you need to do is add to `app/assets/stylesheets/application.scss`
|
92
|
+
|
93
|
+
```
|
94
|
+
@import "bootstrap";
|
95
|
+
```
|
96
|
+
|
97
|
+
## 3. HOTGLUE INSTALLER
|
98
|
+
Add `gem 'hot-glue'` to your Gemfile & `bundle install`
|
99
|
+
|
100
|
+
Purchase a license at https://heliosdev.shop/hot-glue-license
|
101
|
+
|
102
|
+
During in installation, you MUST supply a `--layout` flag.
|
103
|
+
|
104
|
+
### `--layout` flag
|
105
|
+
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).
|
106
|
+
|
107
|
+
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)
|
108
|
+
|
109
|
+
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.
|
110
|
+
|
111
|
+
|
112
|
+
If instead you install Hot Glue (or switch the setting) using the default layout mode (`--layout=hotglue`),
|
113
|
+
your scaffolding will be built using no-Bootstrap syntax: It has its own syntax with classes like
|
114
|
+
`.scaffold-container`,
|
115
|
+
`.scaffold-list`,
|
116
|
+
`.scaffold-row`, and
|
117
|
+
`.scaffold-cell`
|
118
|
+
|
119
|
+
During the installation, if your `--layout` flag is left unspecified or set to `hotglue` you must also pass `--theme` flag.
|
120
|
+
|
121
|
+
the themes are:
|
122
|
+
• like_mountain_view (Google)
|
123
|
+
• like_los_gatos (Netflix)
|
124
|
+
• like_bootstrap (bootstrap 4 copy)
|
125
|
+
• dark_knight (_The Dark Night_ (2008) inspired)
|
126
|
+
• like_cupertino (modern Apple-UX inspired)
|
127
|
+
• gradeschool (spiral bound/lined notebook inspired)
|
128
|
+
|
129
|
+
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.
|
130
|
+
|
131
|
+
(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.)
|
132
|
+
|
133
|
+
The themes are just SCSS files installed into app/assets/stylesheets. You can tweak or modify or remove them after they get installed.
|
134
|
+
|
135
|
+
|
136
|
+
### `--markup` flag
|
137
|
+
|
138
|
+
default is `erb`
|
139
|
+
|
140
|
+
|
141
|
+
## 3. RUN HOT-GLUE INSTALL:
|
142
|
+
### example installing ERB using Bootstrap layout:
|
143
|
+
`rails generate hot_glue:install --markup=erb --layout=bootstrap`
|
144
|
+
|
145
|
+
### Example installing HAML using Hot Glue layout and the 'like_mountain_view' (Gmail-inspired) theme:
|
146
|
+
`rails generate hot_glue:install --markup=erb --layout=hotglue --theme=like_mountain_view`
|
147
|
+
|
148
|
+
|
149
|
+
## 3(B). Modify `application.html.erb`
|
150
|
+
(THIS WAS AUTOMATICALLY DONE BY THE HOT GLUE INSTALLATION -- CONFIRM CHANGES ONLY)
|
151
|
+
Note: if you have some kind of non-standard application layout, like one at a different file
|
152
|
+
or if you have modified your opening <body> tag, this may not have been automatically applied by the installer.
|
153
|
+
|
154
|
+
- This was added to your `application.html.erb`
|
155
|
+
```
|
156
|
+
<%= render partial: 'layouts/flash_notices' %>
|
157
|
+
```
|
158
|
+
|
159
|
+
## 3(C). Modify `rails_helper.rb`
|
160
|
+
(THIS WAS AUTOMATICALLY DONE BY THE HOT GLUE INSTALLATION)
|
161
|
+
Note: if you have some kind of non-standard rails_helper.rb, like one that does not use the standard ` do |config|` syntax after your `RSpec.configure`
|
162
|
+
this may not have been automatically applied by the installer.
|
163
|
+
|
164
|
+
- configure Rspec to work with Factory Bot inside of `rails_helper.rb`
|
165
|
+
```
|
166
|
+
RSpec.configure do |config|
|
167
|
+
// ... more rspec configuration (not shown)
|
168
|
+
config.include FactoryBot::Syntax::Methods
|
169
|
+
end
|
170
|
+
```
|
171
|
+
|
172
|
+
|
173
|
+
## 3(D) CAPYBARA: SWITCH FROM RACK-TEST TO HEADLESS CHROME
|
174
|
+
(THIS WAS AUTOMATICALLY DONE BY THE HOT GLUE INSTALLATION)
|
175
|
+
|
176
|
+
- By default Capybara is installed with :rack_test as its driver.
|
177
|
+
- This does not support Javascript, and the code from Hot Glue IS NOT fallback compatible-- it will not work on non-Javascript browsers.
|
178
|
+
- From the [Capybara docs](https://github.com/teamcapybara/capybara#drivers):
|
179
|
+
```
|
180
|
+
By default, Capybara uses the :rack_test driver, which is fast but limited: it does not support JavaScript
|
181
|
+
```
|
182
|
+
|
183
|
+
- To fix this, you must switch to a Javascript-supporting Capybara driver. You can choose one of:
|
184
|
+
|
185
|
+
`Capybara.default_driver = :selenium`
|
186
|
+
`Capybara.default_driver = :selenium_chrome`
|
187
|
+
`Capybara.default_driver = :selenium_chrome_headless`
|
188
|
+
|
189
|
+
By default, the installer should have added this option to your `rails_helper.rb` file:
|
190
|
+
|
191
|
+
```
|
192
|
+
Capybara.default_driver = :selenium_chrome_headless
|
193
|
+
```
|
194
|
+
|
195
|
+
Alternatively, can define your own driver like so:
|
196
|
+
|
197
|
+
```
|
198
|
+
Capybara.register_driver :my_headless_chrome_desktop do |app|
|
199
|
+
options = Selenium::WebDriver::Chrome::Options.new
|
200
|
+
options.add_argument('--headless')
|
201
|
+
options.add_argument('--disable-gpu')
|
202
|
+
options.add_argument('--window-size=1280,1200')
|
203
|
+
|
204
|
+
driver = Capybara::Selenium::Driver.new(app,
|
205
|
+
browser: :chrome,
|
206
|
+
options: options)
|
207
|
+
|
208
|
+
driver
|
209
|
+
end
|
210
|
+
Capybara.default_driver = :my_headless_chrome_desktop
|
211
|
+
|
212
|
+
```
|
213
|
+
|
214
|
+
|
215
|
+
(THIS WAS ALSO AUTOMATICALLY DONE BY THE HOT GLUE INSTALLATION)
|
216
|
+
|
217
|
+
- for a quick Capybara login, create a support helper in `spec/support/` and log-in as your user
|
218
|
+
- in the default code, the devise login would be for an object called account and lives at the route `/accounts/sign_in`
|
219
|
+
- modify the generated code (it was installed by the installed) for your devise login
|
220
|
+
```
|
221
|
+
def login_as(account)
|
222
|
+
visit '/accounts/sign_in'
|
223
|
+
within("#new_account") do
|
224
|
+
fill_in 'Email', with: account.email
|
225
|
+
fill_in 'Password', with: 'password'
|
226
|
+
end
|
227
|
+
click_button 'Log in'
|
228
|
+
end
|
229
|
+
```
|
230
|
+
|
231
|
+
|
232
|
+
## 4. install font-awesome (optional)
|
233
|
+
|
234
|
+
I recommend
|
235
|
+
https://github.com/tomkra/font_awesome5_rails
|
236
|
+
or
|
237
|
+
https://github.com/FortAwesome/font-awesome-sass
|
238
|
+
|
239
|
+
|
240
|
+
## 5. Devise
|
241
|
+
|
242
|
+
(or only use --gd mode, see below)
|
243
|
+
|
244
|
+
Add to your Gemfile
|
245
|
+
|
246
|
+
As of 2021-12-28 Devise for Rails 7 is still not released so you must use main branch, like so:
|
247
|
+
`gem 'devise', branch: 'main', git: 'https://github.com/heartcombo/devise.git'`
|
248
|
+
|
249
|
+
If on Rails 6 **or** Rails 7, you must do the steps in **Legacy Step #5** (below).
|
250
|
+
|
251
|
+
(If you are on Rails 6, you must do ALL of the steps in the Legacy Setup steps.)
|
252
|
+
|
253
|
+
To be clear: You CAN use Devise with Rails 7, but you must still do the Legacy Step #5 described below for your login to work.
|
254
|
+
|
255
|
+
```
|
256
|
+
rails generate devise:install
|
257
|
+
```
|
258
|
+
|
259
|
+
IMPORTANT: Follow the instructions the Devise installer gives you, *Except Step 3*, you can skip this step:
|
260
|
+
```
|
261
|
+
3. Ensure you have flash messages in app/views/layouts/application.html.erb.
|
262
|
+
For example:
|
263
|
+
|
264
|
+
<p class="notice"><%= notice %></p>
|
265
|
+
<p class="alert"><%= alert %></p>
|
266
|
+
|
267
|
+
```
|
268
|
+
|
269
|
+
|
270
|
+
As described in Legacy Step #5, **you cannot** skip Devise installer Step 4, even though the installer tells you it is optional:
|
271
|
+
```
|
272
|
+
4. You can copy Devise views (for customization) to your app by running:
|
273
|
+
|
274
|
+
rails g devise:views
|
275
|
+
|
276
|
+
```
|
277
|
+
Once you copy the files, you must modify the Devise views to disable Turbo as described in Legacy Step #5.
|
278
|
+
|
279
|
+
|
280
|
+
## LEGACY SETUP FOR RAILS 6
|
281
|
+
|
282
|
+
(Note Legacy Step #5 is necessary for BOTH Rails 6 and Rails 7.)
|
283
|
+
|
284
|
+
|
285
|
+
## Legacy Step #1. ADD HOTWIRE
|
286
|
+
(RAILS 6 ONLY— SKIP THIS STEP FOR RAILS 7)
|
287
|
+
```
|
288
|
+
yarn add @hotwired/turbo-rails
|
289
|
+
```
|
290
|
+
or `npm install @hotwired/turbo-rails`
|
291
|
+
|
292
|
+
|
293
|
+
## Legacy Step #2. SWITCH FROM TurblLinks to Turbo-Rails
|
294
|
+
(RAILS 6 ONLY — SKIP FOR RAILS 7)
|
295
|
+
(THIS WAS AUTOMATICALLY DONE BY THE HOT GLUE INSTALLATION -- CONFIRM CHANGES ONLY)
|
296
|
+
- Add `gem 'turbo-rails'` to your Gemfile & `bundle install`
|
297
|
+
- Then install it with `rails turbo:install`
|
298
|
+
- The Turbo install has switched your action cable settings from 'async' to Redis, so be sure to start a redis server
|
299
|
+
- in `app/javascript/packs/application.js` remove this line
|
300
|
+
```
|
301
|
+
import Turbolinks from "turbolinks"
|
302
|
+
```
|
303
|
+
and replace it with
|
304
|
+
```
|
305
|
+
import { Turbo } from "@hotwired/turbo-rails"
|
306
|
+
```
|
307
|
+
|
308
|
+
|
309
|
+
Also replace
|
310
|
+
```
|
311
|
+
Turbolinks.start()
|
312
|
+
```
|
313
|
+
with:
|
314
|
+
```
|
315
|
+
Turbo.start()
|
316
|
+
```
|
317
|
+
|
318
|
+
|
319
|
+
## Legacy Step #3. INSTALL WEBPACKER
|
320
|
+
(_SKIP FOR RAILS 7_ unless you want to use Webpacker with Rails 7)
|
321
|
+
|
322
|
+
** For webpacker, you must be using Node version ^12.13.0 || ^14.15.0 || >=16 **
|
323
|
+
|
324
|
+
I recommend Node Version Manager (NVM) to switch between nodes. You will not be able to get through the following command with a Node version that does not match above.
|
325
|
+
|
326
|
+
Check your node version with `node -v`
|
327
|
+
|
328
|
+
```
|
329
|
+
`yarn add @rails/webpacker`
|
330
|
+
```
|
331
|
+
|
332
|
+
|
333
|
+
rails webpacker:install
|
334
|
+
|
335
|
+
## Legacy Step #4: ENUM Support
|
336
|
+
For Enum support, I recommend activerecord-pg_enum
|
337
|
+
Instructions for Rails 6 are here:
|
338
|
+
https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
|
339
|
+
|
340
|
+
_This functionality is now built-in to Rails 7._
|
341
|
+
|
342
|
+
|
343
|
+
## Legacy Step #5-- Fix Devise if adding Turbo To Your Project
|
344
|
+
## IMPORTANT: Devise currently has serious compatibility issues with Turbo Rails. In particular, your log-in screens do not work out of the box. Follow the next step to fix them.
|
345
|
+
|
346
|
+
Manually port the Devise views into your app with
|
347
|
+
|
348
|
+
`rails generate devise:views`
|
349
|
+
|
350
|
+
Edit `devise/registrations/new`, `devise/sessions/new`, `devise/passwords/new` and `devise/confirmations/new` modifying all four templates like so:
|
351
|
+
|
352
|
+
form_for(resource, as: resource_name, url: session_path(resource_name) ) do |f|
|
353
|
+
|
354
|
+
|
355
|
+
|
356
|
+
add the data-turbo false option in the html key:
|
357
|
+
|
358
|
+
|
359
|
+
form_for(resource, as: resource_name, **html: {'data-turbo' => "false"},** url: session_path(resource_name) ) do |f|
|
360
|
+
|
361
|
+
|
362
|
+
|
363
|
+
This tells Devise to fall back to non-Turbo interaction for the log-in and registration. For the rest of the app, we will use Turbo Rails interactions.
|
364
|
+
|
365
|
+
|
366
|
+
---
|
367
|
+
---
|
368
|
+
|
369
|
+
|
370
|
+
# HOT GLUE DOCS
|
371
|
+
|
372
|
+
|
373
|
+
## First Argument
|
374
|
+
(no double slash)
|
375
|
+
|
376
|
+
TitleCase class name of the thing you want to build a scaffoling for.
|
377
|
+
|
378
|
+
|
379
|
+
## Options With Arguments
|
380
|
+
|
381
|
+
All options two dashes (--) and these take an `=` and a value
|
382
|
+
|
383
|
+
### `--namespace=`
|
384
|
+
|
385
|
+
pass `--namespace=` as an option to denote a namespace to apply to the Rails path helpers
|
386
|
+
|
387
|
+
|
388
|
+
`rails generate hot_glue:scaffold Thing --namespace=dashboard`
|
389
|
+
|
390
|
+
This produces several views at `app/views/dashboard/things/` and a controller at`app/controllers/dashboard/things_controller.rb`
|
391
|
+
|
392
|
+
The controller looks like so:
|
393
|
+
|
394
|
+
```
|
395
|
+
class Dashboard::ThingsController < ApplicationController
|
396
|
+
before_action :authenticate_user!
|
397
|
+
before_action :load_thing, only: [:show, :edit, :update, :destroy]
|
398
|
+
def load_thing
|
399
|
+
@thing = current_user.things.find(params[:id])
|
400
|
+
end
|
401
|
+
...
|
402
|
+
end
|
403
|
+
|
404
|
+
```
|
405
|
+
|
406
|
+
|
407
|
+
### `--nest=`
|
408
|
+
|
409
|
+
pass `--nest=` to denote a nested resources
|
410
|
+
|
411
|
+
|
412
|
+
`rails generate hot_glue:scaffold Line --nest=invoice`
|
413
|
+
|
414
|
+
In this example, it is presumed that the current user has_many :invoices, and that invoices have many :lines
|
415
|
+
|
416
|
+
|
417
|
+
For multi-level nesting use slashes to separate your levels of nesting. Remember, you should match what you have in your routes.rb file.
|
418
|
+
|
419
|
+
```
|
420
|
+
resources :invoices do
|
421
|
+
resources :lines do
|
422
|
+
resources :charge
|
423
|
+
end
|
424
|
+
end
|
425
|
+
|
426
|
+
```
|
427
|
+
In this example, it is presumed that the current user has_many :invoices, and that invoices have many :lines, and that lines have many :charges
|
428
|
+
|
429
|
+
|
430
|
+
To generate scaffold:
|
431
|
+
`rails generate hot_glue:scaffold Charge --nest=invoice/line`
|
432
|
+
|
433
|
+
The order of the nest should match the nested resources you have in your own app. In particular, you auth root will be used as the starting point when loading the objects from the URL:
|
434
|
+
|
435
|
+
In the example above, @invoice will be loaded from
|
436
|
+
|
437
|
+
`@invoice = current_user.invoices.find(params[:invoice_id])`
|
438
|
+
|
439
|
+
Then, @line will be loaded
|
440
|
+
|
441
|
+
`@line = @invoice.lines.find(params[:line_id])`
|
442
|
+
|
443
|
+
Then, finally the @charge will be loaded
|
444
|
+
|
445
|
+
`@charge = @line.charges.find(params[:id])`
|
446
|
+
|
447
|
+
It's called "poor man's access control" because if a user attempts to hack the URL by passing ids for objects they don't own--- which Rails makes relatively easy with its default URL pattern-- they will hit ActiveRecord not found errors (the objects they don't own won't be found in the associated relationship).
|
448
|
+
|
449
|
+
It works, but it isn't granular. As well, it isn't appropriate for a large app with any level of intricacy to access control (that is, having roles).
|
450
|
+
|
451
|
+
Your customers can delete their own objects by default (may be a good idea or a bad idea for you). If you don't want that, you should strip out the delete actions off the controllers.
|
452
|
+
|
453
|
+
|
454
|
+
### `--auth=`
|
455
|
+
|
456
|
+
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.
|
457
|
+
|
458
|
+
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.
|
459
|
+
|
460
|
+
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.
|
461
|
+
|
462
|
+
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.
|
463
|
+
|
464
|
+
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.
|
465
|
+
|
466
|
+
If you use a different object other than "User" for authentication, override using the `auth` option.
|
467
|
+
|
468
|
+
`rails generate hot_glue:scaffold Thing --auth=current_account`
|
469
|
+
|
470
|
+
You will note that in this example it is presumed that the Account object will have an association for `things`
|
471
|
+
|
472
|
+
It is also presumed that when viewing their own dashboard of things, the user will want to see ALL of their associated things.
|
473
|
+
|
474
|
+
If you supply nesting (see below), your nest chain will automatically begin with your auth root object (see nesting)
|
475
|
+
|
476
|
+
|
477
|
+
|
478
|
+
|
479
|
+
### `--auth_identifier=`
|
480
|
+
|
481
|
+
Your controller will call a method authenticate_ (AUTH IDENTIFIER) bang, like:
|
482
|
+
|
483
|
+
`authenticate_user!`
|
484
|
+
|
485
|
+
Before all of the controller actions. If you leave this blank, it will default to using the variable name supplied by auth with "current_" stripped away.
|
486
|
+
(This is setup for devise.)
|
487
|
+
|
488
|
+
Be sure to implement the following method in your ApplicationController or some other method. Here's a quick example using Devise. You will note in the code below, user_signed_in? is implemented when you add Devise methods to your User table.
|
489
|
+
|
490
|
+
As well, the `after_sign_in_path_for(user)` here is a hook for Devise also that provides you with after login redirect to the page where the user first intended to go.
|
491
|
+
|
492
|
+
```
|
493
|
+
def authenticate_user!
|
494
|
+
if ! user_signed_in?
|
495
|
+
session['user_return_to'] = request.path
|
496
|
+
redirect_to new_user_registration_path
|
497
|
+
end
|
498
|
+
end
|
499
|
+
|
500
|
+
def after_sign_in_path_for(user)
|
501
|
+
session['user_return_to'] || account_url(user)
|
502
|
+
end
|
503
|
+
```
|
504
|
+
|
505
|
+
|
506
|
+
The default (do not pass `auth_identifier=`) will match the `auth` (So if you use 'account' as the auth, `authenticate_account!` will get invoked from your generated controller; the default is always 'user', so you can leave both auth and auth_identifier off if you want 'user')
|
507
|
+
|
508
|
+
|
509
|
+
`rails generate hot_glue:scaffold Thing --auth=current_account --auth_identifier=login`
|
510
|
+
In this example, the controller produced with:
|
511
|
+
```
|
512
|
+
before_action :authenticate_login!
|
513
|
+
```
|
514
|
+
However, the object graph anchors would continue to start from current_account. That is,
|
515
|
+
```
|
516
|
+
@thing = current_account.things.find(params[:id])
|
517
|
+
```
|
518
|
+
|
519
|
+
Use empty string to **turn this method off**:
|
520
|
+
`rails generate hot_glue:scaffold Thing --auth=current_account --auth_identifier=''`
|
521
|
+
|
522
|
+
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.
|
523
|
+
|
524
|
+
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.
|
525
|
+
|
526
|
+
|
527
|
+
### `--plural=`
|
528
|
+
|
529
|
+
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)
|
530
|
+
|
531
|
+
|
532
|
+
### `--exclude=`
|
533
|
+
(separate field names by COMMA)
|
534
|
+
|
535
|
+
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.)
|
536
|
+
|
537
|
+
If you specify an exclude list, those and the default excluded list will be excluded.
|
538
|
+
|
539
|
+
|
540
|
+
`rails generate hot_glue:scaffold Account --exclude=password`
|
541
|
+
|
542
|
+
(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.)
|
543
|
+
|
544
|
+
|
545
|
+
### `--include=`
|
546
|
+
Separate field names by COMMA
|
547
|
+
|
548
|
+
If you specify an include list, it will be treated as a whitelist: no fields will be included unless specified on the include list.
|
549
|
+
|
550
|
+
`rails generate hot_glue:scaffold Account --include=first_name,last_name,company_name,created_at,kyc_verified_at`
|
551
|
+
|
552
|
+
Separate COLUMNS by a COLON
|
553
|
+
If you want to group up fields together into columns, use a COLON (`:`) character to specify columns.
|
554
|
+
Your input may have a COLON at the end of it, but otherwise your columns will made flush left.
|
555
|
+
|
556
|
+
Without colons, no group will happen, so these two fields would display in two columns:
|
557
|
+
`--include=api_id,api_key`
|
558
|
+
|
559
|
+
With a trailing colon, you're telling Hot Glue to make the two fields into column #1. (Here, there is no other column.)
|
560
|
+
`--include=api_id,api_key:`
|
561
|
+
|
562
|
+
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:
|
563
|
+
`--include=name:api_id,api_key`
|
564
|
+
|
565
|
+
Specifying any colon in your include syntax switches the builder into 12-column mode, whereas without you might create more than 12 columns if there are too many feilds for the available columns on the layout.
|
566
|
+
|
567
|
+
You may not specify both include and exclude.
|
568
|
+
|
569
|
+
|
570
|
+
### `--show-only=`
|
571
|
+
(separate field names by COMMA)
|
572
|
+
|
573
|
+
Any fields only the 'show-only' list will appear as non-editable on the generate form. (visible only)
|
574
|
+
|
575
|
+
IMPORTANT: By default, all fields that begin with an underscore (`_`) are automatically show-only.
|
576
|
+
|
577
|
+
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.
|
578
|
+
|
579
|
+
### `--ujs_syntax=true` (Default is set automatically based on whether you have turbo-rails installed)
|
580
|
+
|
581
|
+
If you are pre-Turbo (UJS), your delete buttons will come out like this:
|
582
|
+
`data: {'confirm': 'Are you sure you want to delete....?'}`
|
583
|
+
|
584
|
+
If you are Turbo (Rails 7 or Rails 6 with proactive Turbo-Rails install), your delete button will be:
|
585
|
+
`data: {'turbo-confirm': 'Are you sure you want to delete....?'}`
|
586
|
+
|
587
|
+
If you specify the flag, you preference will be used. If you leave the flag off, Hot Glue will detect the presence of Turbo-Rails in your app.
|
588
|
+
|
589
|
+
**WARNING**: If you created a new Rails app since October 2021 and you have the yanked turbo-rails Gems on your local machine,
|
590
|
+
you will have some bugs with the delete buttons and also not be on the latest version of turbo-rails.
|
591
|
+
|
592
|
+
Make sure to uninstall the yanked 7.1.0 and 7.1.1 from your machine with `gem uninstall turbo-rails`
|
593
|
+
and also fix any Rails apps created since October 2021 by fixing the Gemfile. Details here:
|
594
|
+
https://stackoverflow.com/questions/70671324/new-rails-7-turbo-app-doesnt-show-the-data-turbo-confirm-alert-messages-dont-f
|
595
|
+
|
596
|
+
|
597
|
+
### `--magic-buttons`
|
598
|
+
If you pass a list of magic buttons (separated by commas), they will appear in the button area on your list.
|
599
|
+
|
600
|
+
It will be assumed there will be corresponding bang methods on your models.
|
601
|
+
|
602
|
+
The bang (`!`) methods can respond in one of four ways:
|
603
|
+
|
604
|
+
• With true, in which case a generic success message will be shown in the flash notice (“Approved” or “Rejected” in this case)
|
605
|
+
|
606
|
+
• With false, in which case a generic error message will be shown in the flash alert (“Could not approve…”)
|
607
|
+
|
608
|
+
• With a string, which will be assumed to be a “success” case, and will be passed to the front-end in the alert notice.
|
609
|
+
|
610
|
+
• Raise an ActiveRecord exception
|
611
|
+
|
612
|
+
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.
|
613
|
+
|
614
|
+
Finally, you can raise an ActiveRecord error which will also get passed to the user, but in the flash alert area
|
615
|
+
|
616
|
+
For more information see Example 5 in the Tutorial
|
617
|
+
|
618
|
+
|
619
|
+
### `--downnest`
|
620
|
+
|
621
|
+
Automatically create subviews down your object tree. This should be the name of a has_many relationship based from the current object.
|
622
|
+
You will need to build scaffolding with the same name for the related object as well.
|
623
|
+
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.
|
624
|
+
|
625
|
+
|
626
|
+
### `--alt-controller-name`
|
627
|
+
|
628
|
+
Normally a controller a has a natural name based on the model (the Thing model produces a `ThingsController`).
|
629
|
+
|
630
|
+
Within any given namespace, you can have only one natural controller for that model, of course, because all the controllers exist at the namespace directory even when they are nested.
|
631
|
+
|
632
|
+
For example, let's say you have an Admin dashboard with User has_many :invoices
|
633
|
+
|
634
|
+
Your routes file will nest your invoices within your users (for whatever namespace you are building)
|
635
|
+
|
636
|
+
```
|
637
|
+
namespace :admin do
|
638
|
+
resources :users do
|
639
|
+
resources :invoices
|
640
|
+
end
|
641
|
+
end
|
642
|
+
```
|
643
|
+
|
644
|
+
Therefore, your namespace can typically only view that model in one context. If that context is nested (using `--nest` exists at a nested route), it can only be used in the context of that nest (which probably requires one or more parent objects to be in the nested route of your URL).
|
645
|
+
|
646
|
+
You should preserve this naming convention, and stay within those guides so your nested routes work when this object is nested within another object's view. (For the context of that or any namespace.)
|
647
|
+
|
648
|
+
Alternative controller names let you specify a controller name that is nameed _something else_ but still edits the given object/table.
|
649
|
+
|
650
|
+
In the example above, you'd add another top-level route in the same namespace called "all_X".
|
651
|
+
|
652
|
+
For example,
|
653
|
+
|
654
|
+
**config/routes.rb**
|
655
|
+
```
|
656
|
+
namespace :admin do
|
657
|
+
resources :users do
|
658
|
+
resources :invoices
|
659
|
+
end
|
660
|
+
resources :all_invoices
|
661
|
+
end
|
662
|
+
```
|
663
|
+
|
664
|
+
Then you'd build normal nested scaffold like so:
|
665
|
+
|
666
|
+
```
|
667
|
+
rails generate hot_glue:scaffold User --namespace=admin --gd
|
668
|
+
|
669
|
+
rails generate hot_glue:scaffold Invoice --namespace=admin --nest=users --gd
|
670
|
+
|
671
|
+
```
|
672
|
+
You'd build another Invoices controller like this:
|
673
|
+
|
674
|
+
```
|
675
|
+
rails generate hot_glue:scaffold Invoice --namespace=admin --alt-controller-name=AllInvoices --gd
|
676
|
+
```
|
677
|
+
|
678
|
+
Note that all three builds here are in the `admin` namespace (so build controllers at `app/controllers/admin/`) and ALSO use Gd mode.
|
679
|
+
|
680
|
+
If you extend the example conceptually you build things like "UnpaidInvoices" or "RecentInvoices" which would, for example, build contextual views for the admin user.
|
681
|
+
|
682
|
+
The difference between the one kind of Invoices controller and the other is that, in this example, the InvoicesController (the natural one) is always nested to the user. So if you ever want to know about invoices in the context of a user, that's exactly what you use.
|
683
|
+
|
684
|
+
The other one, `AllInvoicesController` or `UnpaidInvoicesController` will provide the admin a view of invoices **out of the context** of the user object.
|
685
|
+
|
686
|
+
|
687
|
+
|
688
|
+
|
689
|
+
|
690
|
+
|
691
|
+
## FLAGS (Options with no values)
|
692
|
+
These options (flags) also uses `--` syntax but do not take any values. Everything is assumed (default) to be false unless specified.
|
693
|
+
|
694
|
+
### `--god` or `--gd`
|
695
|
+
|
696
|
+
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.
|
697
|
+
|
698
|
+
For example, FOR ADMIN CONTROLLERS ONLY, supply a auth_identifier and use `--god` flag.
|
699
|
+
|
700
|
+
In Gd mode, the objects are loaded directly from the base class (these controllers have full access)
|
701
|
+
```
|
702
|
+
def load_thing
|
703
|
+
@thing = Thing.find(params[:id])
|
704
|
+
end
|
705
|
+
|
706
|
+
```
|
707
|
+
|
708
|
+
|
709
|
+
### `--specs-only`
|
710
|
+
|
711
|
+
Produces ONLY the controller spec file, nothing else.
|
712
|
+
|
713
|
+
|
714
|
+
### `--no-specs`
|
715
|
+
|
716
|
+
Produces all the files except the spec file.
|
717
|
+
|
718
|
+
|
719
|
+
### `--no-paginate`
|
720
|
+
|
721
|
+
Omits pagination. (All list views have pagination by default.)
|
722
|
+
|
723
|
+
### `--no-list`
|
724
|
+
|
725
|
+
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.
|
726
|
+
|
727
|
+
|
728
|
+
### `--no-list-labels`
|
729
|
+
|
730
|
+
Omits list labels. (note that in the form the labels are rendered again anyway)
|
731
|
+
|
732
|
+
### `--no-create`
|
733
|
+
|
734
|
+
Omits create action.
|
735
|
+
|
736
|
+
### `--no-delete`
|
737
|
+
|
738
|
+
Omits delete action.
|
739
|
+
|
740
|
+
### `--big-edit`
|
741
|
+
|
742
|
+
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.
|
743
|
+
|
744
|
+
### `--display-list-after-update` (default: false)
|
745
|
+
|
746
|
+
After an update-in-place normally only the edit view is swapped out for the show view of the record you just edited.
|
747
|
+
|
748
|
+
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).
|
749
|
+
|
750
|
+
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.
|
751
|
+
|
752
|
+
### `--smart-layout` (default: false)
|
753
|
+
|
754
|
+
|
755
|
+
|
756
|
+
|
757
|
+
## Automatic Base Controller
|
758
|
+
|
759
|
+
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.
|
760
|
+
|
761
|
+
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.
|
762
|
+
|
763
|
+
## Field Types Supported
|
764
|
+
|
765
|
+
- Integers that don't end with `_id`, they will be displayed as text fields.
|
766
|
+
- 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.)
|
767
|
+
- String*
|
768
|
+
- Text*
|
769
|
+
- Float*
|
770
|
+
- Datetime
|
771
|
+
- Date
|
772
|
+
- Time
|
773
|
+
- Boolean
|
774
|
+
- Enum - will display as a value list populated from the enum list defined on your model. see https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
|
775
|
+
|
776
|
+
* shows in a size-aware container, i.e. in a bigger box if the field allows for more content
|
777
|
+
|
778
|
+
|
779
|
+
|
780
|
+
# VERSION HISTORY
|
781
|
+
|
782
|
+
#### 2022-01-11 - v0.4.5 - buttons on smarty layouts take up 1 bootstrap column each; fixes confirmation alert for delete buttons
|
783
|
+
|
784
|
+
#### 2022-01-01 - v0.4.3 and 0.4.4 - adding fully email based license; no activation codes required
|
785
|
+
|
786
|
+
#### 2022-12-30 - v0.4.2 -- Smart layouts introduced
|
787
|
+
|
788
|
+
#### 2021-12-15 - v0.4.1
|
789
|
+
|
790
|
+
#### 2021-12-12 - v0.4.0
|
791
|
+
|
792
|
+
#### 2021-12-12 - v0.3.9 - Magic Buttons
|
793
|
+
|
794
|
+
#### 2021-12-11 - v0.3.5 - Downnesting
|
795
|
+
|
796
|
+
|
797
|
+
#### 2021-11-27 - v0.2.9E — EXPERIMENTAL
|
798
|
+
- Downnesting
|
799
|
+
- Adds spec coverage support for enums
|
800
|
+
- Several more fixes; this is preparation for forthcoming release.
|
801
|
+
- Some parts still experimental. Use with caution.
|
802
|
+
|
803
|
+
#### 2021-10-11 - v0.2.6 - many additional automatic fixes for default Rails installation 6 or 7 for the generate hot_glue:install command
|
804
|
+
|
805
|
+
|
806
|
+
#### 2021-10-10 - v0.2.5 - this version is all about developer happyness:
|
807
|
+
- significant fixes for the behavioral (system) specs. they now create new & update interactions
|
808
|
+
for (almost) all field types
|
809
|
+
- the install generator now checks your layouts/application.html.erb for `render partial: 'layouts/flash_messages' ` and adds it if it isn't there already
|
810
|
+
- the install generator also checks your spec/rails_helper for `config.include FactoryBot::Syntax::Methods` and adds it at the top of the Rspec configure block if it isn't there
|
811
|
+
|
812
|
+
#### 2021-10-07 - v0.2.4 - removes erroneous icons display in delete buttos (these don't work inside of button_to);
|
813
|
+
- adds support for ENUM types direclty on your field types
|
814
|
+
- you must use activerecord-pgenum
|
815
|
+
- see my blog post at https://jasonfleetwoodboldt.com/courses/stepping-up-rails/enumerated-types-in-rails-and-postgres/
|
816
|
+
|
817
|
+
#### 2021-09-30 - v0.2.3 - fixes ERB output for show-only fields; fixes flash_notices for erb or haml; adds @stimulus_syntax flag for delete confirmations with stimulus
|
818
|
+
|
819
|
+
#### 2021-09-27 - v0.2.2 - Fixes some issues with related fields; unlocks Rails 7 in Gemspec file
|
820
|
+
|
821
|
+
#### 2021-09-20 - v0.2.1 - Fixes nesting behavior when using gd option
|
822
|
+
|
823
|
+
#### 2021-09-06 - v0.2.0 - ERB or HAML; use the option --markup=erb or --markup=haml (default is now erb)
|
824
|
+
|
825
|
+
#### 2021-06-28 - v0.1.2 - fixes problem with namespaces on path helpers
|
826
|
+
|
827
|
+
#### 2021-05-09 (yanked) - v0.1.1 - add cancellation buttons
|
828
|
+
|
829
|
+
#### 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"
|
830
|
+
|
831
|
+
#### 2021-03-24 - v0.0.9 - fixes in the automatic field label detection; cleans up junk in spec output
|
832
|
+
|
833
|
+
#### 2021-03-21 - v0.0.8 - show only flag; more specific spec coverage in generator spec
|
834
|
+
|
835
|
+
#### 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
|
836
|
+
|
837
|
+
#### 2021-03-06 - v0.0.6 - internal specs test the error catches and cover basic code generation (dummy testing only)
|
838
|
+
|
839
|
+
#### 2021-03-01 - v0.0.5 - Validation magic; refactors the options to the correct Rails::Generators syntax
|
840
|
+
|
841
|
+
#### 2021-02-27 - v0.0.3 - several fixes for namespaces; adds pagination; adds exclude list to fields
|
842
|
+
|
843
|
+
#### 2021-02-25 - v0.0.2 - bootstrapy
|
844
|
+
|
845
|
+
#### 2021-02-24 - v0.0.1 - first proof of concept release -- basic CRUD works
|
846
|
+
|
847
|
+
|
848
|
+
|
849
|
+
|
850
|
+
|
851
|
+
|
1
852
|
# HOW THIS GEM IS TESTED
|
2
853
|
|
3
854
|
SETUP:
|