hot-glue 0.0.9 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 831970726374d97ef6b5380d122033384777a520ba5fcaeebc9ee79717b82ef1
4
- data.tar.gz: f45f7a48e78a6bfd62973a11d5b55b24d7ba7a7979855940429ea00398e3ef1f
3
+ metadata.gz: 88c8ae8859f5a37ed898fb4047ab2a406c5eacbb766bcbf6dc2b43f5d419b751
4
+ data.tar.gz: 8685951b462a1b9c0f3e5920b193e057a15a2d497d103bf163702dfdbfa4f89f
5
5
  SHA512:
6
- metadata.gz: 23fa8de6cc6460b36d3a867c502a708c6ea825575f25240d28f11f0c0f5a333fc6fe583fa95668d517555bbef96177407432a8c98ca41a29caeca82fa37e765a
7
- data.tar.gz: a1c9db09d05ab741a85906e31b9cc5336c73f4108f550edbd14166d00f0623b65b1ea8c97a8b9c95c39de55a72bc006cb657ab3d5cddff17258983eb26183ccc
6
+ metadata.gz: 54f3cbd725a0ca775b688405d8f00b0aa5611a4bd2d2bbb0566bb72fcf8a1c532e3dc88684e55a0c63dd300c0f0f0f9549f5536b74fba36714f5c97a14467c18
7
+ data.tar.gz: 269fe5314a3acbc91591efea6b2f43e049244152bfb6e1c803b67c0d4b233a461cf2131fe4825a331e205c830ee7961ba78d7c6b617374291e8c9ebb63952735
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.0.8)
4
+ hot-glue (0.0.9)
5
5
  ffaker (~> 2.16)
6
6
  haml-rails (~> 2.0)
7
7
  kaminari (~> 1.2)
data/README.md CHANGED
@@ -1,77 +1,118 @@
1
1
  # Hot Glue
2
2
 
3
- Hot Glue is an evolution of the best of the admin-style scaffold builders 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) being the most popular of those). It harnesses the power of Rails 6, Turbo-Rails, and Hotwire to deliver a lightning fast experience.
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
- As well, its premise is a little different than the configuration-heavy admin interface toolkits. 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.
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 gives users full control over objects they 'own' and by default it spits out functionality giving access to all fields.
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
- Hot Glue generates functionality that's quick and dirty. It let's you be crafty. As with a real glue gun, take care not to burn yourself while using it.
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
- * Build plug-and-play scaffolding mixing HAML and turbo_stream responses
12
- * Automatically Reads Your Models (make them before building your scaffolding!)
13
- * CRUD, lists with pagination, (coming soon: sorting & searching)
14
- * Wonderful for prototyping.
15
- * Nest your routes model-by-model for built-in poor man's authentication.
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
- * Requires & uses Kaminari for pagination.
18
- * Create specs automatically along with the controllers (* rspec only for now).
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 (COMING SOON)
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://blog.jasonfleetwoodboldt.com/hot-glue
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 Turbo-Rails to your Gemfile & bundle install
51
+ - Add `gem 'turbo-rails'` to your Gemfile & `bundle install`
39
52
 
40
53
  - Then install it with `rails turbo:install`
41
54
 
42
55
  - The Turbo install has switched your action cable settings from 'async' to Redis, so be sure to start a redis server
43
56
 
44
- - Add `hot_glue` to your Gemfile & `bundle install`
57
+ - Add `gem 'hot-glue'` to your Gemfile & `bundle install`
45
58
 
46
- - Then install it with `rails generate hot_glue:install`
59
+ - Run the hot-glue installation with `rails generate hot_glue:install`
47
60
 
48
61
  - Add to your `application.html.erb`
49
62
  ```
50
63
  <%= render partial: 'layouts/flash_notices' %>
51
64
  ```
52
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
+
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
+
53
92
  - Install Bootstrap (optional)
54
93
 
55
94
  Bootstrap with Webpack:
56
95
  - change `stylesheet_link_tag` to `stylesheet_pack_tag` in your application layout
57
- - `yarn add bootstrap`
58
- - create a new file at `app/javascript/css/site.scss` with this content
96
+ - run `yarn add bootstrap`
97
+ - create a new file at `app/javascript/require_bootstrap.scss` with this content
59
98
  ```
60
99
  @import "~bootstrap/scss/bootstrap.scss";
61
100
  ```
62
101
 
63
102
  - add to `app/javascript/packs/application.js`
64
103
  ```
65
- import 'css/site'
104
+ import 'require_bootstrap'
66
105
  ```
67
106
 
68
107
  Bootstrap with Sprockets:
69
- - use bootstrap-rails gem
70
-
108
+ - use bootstrap-rubygem gem
109
+ - see README for bootstrap-rubygem to install
110
+
71
111
 
72
112
  - Install Devise or implement your own authentication
113
+ (or only use --gd mode, see below)
73
114
 
74
- - Also recommended: font-awesome-sass
115
+ - font-awesome
75
116
 
76
117
 
77
118
  ### First Argument
@@ -313,6 +354,8 @@ If you do not want inline editing of your list items but instead to fall back to
313
354
 
314
355
  # VERSION HISTORY
315
356
 
357
+ #### 2021-04-28 - v0.1.0 - Very please to introduce full behavior specs, found in specs/system/, generated by default on all build code; also many fixes involving nesting and authentication"
358
+
316
359
  #### 2021-03-24 - v0.0.9 - fixes in the automatic field label detection; cleans up junk in spec output
317
360
 
318
361
  #### 2021-03-21 - v0.0.8 - show only flag; more specific spec coverage in generator spec
@@ -334,20 +377,12 @@ If you do not want inline editing of your list items but instead to fall back to
334
377
  #### 2021-02-23 - v0.0.0 - Port of my prior work from github.com/jasonfb/common_core_js
335
378
 
336
379
 
337
- # ACKNOWLEDGEMENTS
338
-
339
- ### "POOR MAN"
340
-
341
- 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)!
342
-
343
380
 
344
381
 
345
382
 
346
383
  # HOW THIS GEM IS TESTED
347
384
 
348
- The testing of functionality-within-functionality is a little tricky and requires thinking outside the box.
349
-
350
- We have two kinds of "sandboxes": a DUMMY sandbox, and also a STRAWMAN sandbox
385
+ We have one kind of "sandboxes": a DUMMY sandbox
351
386
 
352
387
  The dummy sandbox is found at `spec/dummy`
353
388
 
@@ -355,20 +390,5 @@ The dummy lives as mostly checked- into the repository, except the folders where
355
390
 
356
391
  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.
357
392
 
358
-
359
393
  The DUMMY testing DOES NOT test the actual functionality of the output code (it just tests the functionality of the generation process).
360
394
 
361
- For this reason, I've also added something I call STRAWMAN testing, which is a set of steps that does these things:
362
-
363
- The Strawman isn't in the repository, but if you build it locally, it will create itself into
364
-
365
- `spec/strawman/`
366
-
367
- 1) Builds you a strawman sandbox app from scratch, using the native `rails new`
368
- 2) Makes a few small modifications to the new app to support this gem
369
- 3) Create two nonsense tables called OmnitableA and OmnitableB. Each omnitable has one of each kind of field (integer, text, string, date, time, etc)
370
- 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.
371
- 5) The built app itself will contain its own specs
372
- 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.
373
-
374
-
@@ -0,0 +1,9 @@
1
+ class CreateGhis < ActiveRecord::Migration[6.1]
2
+ def change
3
+ create_table :ghis do |t|
4
+ t.integer :def_id
5
+
6
+ t.timestamps
7
+ end
8
+ end
9
+ end
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 "hgis", force: :cascade do |t|
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,35 @@ require 'ffaker'
3
3
 
4
4
 
5
5
  module HotGlue
6
-
7
-
8
6
  class Error < StandardError
9
7
  end
10
8
 
11
9
 
10
+
11
+
12
+
12
13
  module GeneratorHelper
14
+ def derrive_reference_name thing_as_string
15
+ assoc_class = eval(thing_as_string)
16
+
17
+ if assoc_class.respond_to?("name")
18
+ display_column = "name"
19
+ elsif assoc_class.respond_to?("to_label")
20
+ display_column = "to_label"
21
+ elsif assoc_class.respond_to?("full_name")
22
+ display_column = "full_name"
23
+ elsif assoc_class.respond_to?("display_name")
24
+ display_column = "display_name"
25
+ elsif assoc_class.respond_to?("email")
26
+ display_column = "email"
27
+ else
28
+ raise("this should have been caught by the checker in the initializer")
29
+ # 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)"
30
+ end
31
+ display_column
32
+ end
33
+
34
+
13
35
  def text_area_output(col, field_length, col_identifier )
14
36
  lines = field_length % 40
15
37
  if lines > 5
@@ -82,9 +104,12 @@ module HotGlue
82
104
  @singular = args.first.tableize.singularize # should be in form hello_world
83
105
  @plural = options['plural'] || @singular + "s" # supply to override; leave blank to use default
84
106
  @auth = options['auth'] || "current_user"
85
- @auth_identifier = options['auth'] || (!@auth.nil? && @auth.gsub("current_", "")) || nil
86
- @nest = options['auth'] || nil
107
+ @auth_identifier = options['auth_identifier'] || (!@auth.nil? && @auth.gsub("current_", "")) || nil
108
+
109
+
110
+ @nest = (!options['nest'].empty? && options['nest']) || nil
87
111
  @namespace = options['namespace'] || nil
112
+
88
113
  @singular_class = @singular.titleize.gsub(" ", "")
89
114
  @exclude_fields = []
90
115
  @exclude_fields += options['exclude'].split(",").collect(&:to_sym)
@@ -154,12 +179,25 @@ module HotGlue
154
179
 
155
180
  if assoc
156
181
  ownership_field = assoc.name.to_s + "_id"
182
+ elsif !@nest
183
+ 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."
184
+
157
185
  else
158
- # if @auth
159
- 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."
160
- # else
161
- # exit_message= "*** Oops: god mode could not find the association(?). something is wrong."
162
- # end
186
+ if @god
187
+
188
+ exit_message= "*** Oops: god mode could not find the association(?). something is wrong."
189
+ else
190
+ @auth_check = "current_user"
191
+ @nested_args.each do |arg|
192
+
193
+ if !@auth_check.method("#{arg}s")
194
+ exit_message= "*** Oops: your nesting chain does not have a assocation for #{arg}s on #{@auth_check} something is wrong."
195
+ end
196
+ byebug
197
+ puts ""
198
+ end
199
+ end
200
+
163
201
  raise(HotGlue::Error, exit_message)
164
202
  end
165
203
  end
@@ -197,7 +235,7 @@ module HotGlue
197
235
  begin
198
236
  eval(assoc.class_name)
199
237
  rescue NameError => e
200
- exit_message = "*** Oops: The table #{singular_class} has an association for '#{assoc.name.to_s}', but I can't find an assoicated model for that association. TODO: Please implement a model for #{assoc.name.to_s} that belongs to #{singular_class} "
238
+ 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."
201
239
  raise(HotGlue::Error, exit_message)
202
240
 
203
241
  end
@@ -242,15 +280,18 @@ module HotGlue
242
280
 
243
281
  unless @specs_only
244
282
  template "controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "#{plural}_controller.rb")
245
- if @namespace && defined?(controller_descends_from) == nil
246
- template "base_controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "base_controller.rb")
283
+ if @namespace
284
+ begin
285
+ eval(controller_descends_from)
286
+ puts " skipping base controller #{controller_descends_from}"
287
+ rescue NameError => e
288
+ template "base_controller.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}app/controllers#{namespace_with_dash}", "base_controller.rb")
289
+ end
247
290
  end
248
291
  end
249
292
 
250
293
  unless @no_specs
251
- template "request_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/request#{namespace_with_dash}", "#{plural}_spec.rb")
252
- template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_spec.rb")
253
-
294
+ template "system_spec.rb.erb", File.join("#{'spec/dummy/' if Rails.env.test?}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
254
295
  end
255
296
 
256
297
  template "_errors.haml", File.join("#{'spec/dummy/' if Rails.env.test?}app/views#{namespace_with_dash}", "_errors.haml")
@@ -329,9 +370,9 @@ module HotGlue
329
370
  end
330
371
 
331
372
 
332
- def path_helper_full
333
- "#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{singular}_path"
334
- end
373
+ # def path_helper_full
374
+ # "#{@namespace+"_" if @namespace}#{(@nested_args.join("_") + "_" if @nested_args.any?)}#{singular}_path"
375
+ # end
335
376
 
336
377
  def path_helper_args
337
378
  if @nested_args.any?
@@ -443,6 +484,9 @@ module HotGlue
443
484
  end
444
485
 
445
486
 
487
+
488
+
489
+
446
490
  def copy_view_files
447
491
  return if @specs_only
448
492
  haml_views.each do |view|
@@ -536,27 +580,11 @@ module HotGlue
536
580
  exit_message= "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
537
581
  exit
538
582
  end
583
+ display_column = derrive_reference_name(assoc.class_name)
539
584
 
540
585
 
541
- assoc_class = eval(assoc.class_name)
542
-
543
- if assoc_class.respond_to?("name")
544
- display_column = "name"
545
- elsif assoc_class.respond_to?("to_label")
546
- display_column = "to_label"
547
- elsif assoc_class.respond_to?("full_name")
548
- display_column = "full_name"
549
- elsif assoc_class.respond_to?("display_name")
550
- display_column = "display_name"
551
- elsif assoc_class.respond_to?("email")
552
- display_column = "email"
553
- else
554
- raise("this should have been caught by the checker in the initializer")
555
- # 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)"
556
- end
557
-
558
586
  "#{col_identifier}{class: \"form-group \#{'alert-danger' if #{singular}.errors.details.keys.include?(:#{assoc_name.to_s})}\"}
559
- #{col_spaces_prepend}= f.collection_select(:#{col.to_s}, #{assoc_class}.all, :id, :#{display_column}, {prompt: true, selected: @#{singular}.#{col.to_s} }, class: 'form-control')
587
+ #{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')
560
588
  #{col_spaces_prepend}%label.small.form-text.text-muted
561
589
  #{col_spaces_prepend} #{col.to_s.humanize}"
562
590
 
@@ -636,25 +664,9 @@ module HotGlue
636
664
  exit_message = "*** Oops. on the #{singular_class} object, there doesn't seem to be an association called '#{assoc_name}'"
637
665
  raise(HotGlue::Error,exit_message)
638
666
  end
639
-
640
- assoc_class = eval(assoc.class_name)
641
667
 
642
- if assoc_class.respond_to?("name")
643
- display_column = "name"
644
- elsif assoc_class.respond_to?("to_label")
645
- display_column = "to_label"
646
- elsif assoc_class.respond_to?("full_name")
647
- display_column = "full_name"
648
- elsif assoc_class.respond_to?("display_name")
649
- display_column = "display_name"
650
- elsif assoc_class.respond_to?("email")
651
- display_column = "email"
652
- elsif assoc_class.respond_to?("number")
653
- display_column = "number"
668
+ display_column = derrive_reference_name(assoc.class_name)
654
669
 
655
- else
656
- 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)"
657
- end
658
670
 
659
671
  "#{col_identifer}
660
672
  = #{singular}.#{assoc.name.to_s}.try(:#{display_column}) || '<span class=\"content alert-danger\">MISSING</span>'.html_safe"
@@ -728,7 +740,7 @@ module HotGlue
728
740
  me = eval(singular_class)
729
741
 
730
742
  @display_class ||=
731
- if me.column_names.include?("name")
743
+ if me.column_names.include?("name") || me.instance_methods(false).include?(:name)
732
744
  # note that all class object respond_to?(:name) with the name of their own class
733
745
  # this one is unique
734
746
  "name"
@@ -742,7 +754,6 @@ module HotGlue
742
754
  "email"
743
755
  elsif me.column_names.include?("number") || me.instance_methods(false).include?(:number)
744
756
  "number"
745
-
746
757
  else
747
758
  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)"
748
759
  raise(HotGlue::Error, exit_message)
@@ -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, <%= path_helper_full %>(<%= path_helper_args %>), method: :delete, data: {confirm: 'Are you sure?'}, disable_with: "Loading...", class: "delete-<%= singular %>-button btn btn-primary "
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
  &nbsp;
7
- = link_to "Edit <i class='fa fa-1x fa-list-alt'></i>".html_safe, edit_<%= path_helper_full %>(<%= path_helper_args %>), <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary "
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
- <% if any_nested? %> <% @nested_args.each do |arg| %>
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" : "@#{nest_chain.last}.#{arg}s"
15
- nest_chain << arg %>def load_<%= arg %>
16
- @<%= arg %> = <%= this_scope %>.find(params[:<%= arg %>_id])
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 !@<%= singular_name %>.update(modify_date_inputs_on_params(<%= singular %>_params<%= @auth ? ', ' + @auth : '' %>))
85
- flash[:alert] = "<%= singular_name.titlecase %> could not be saved"
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,52 +1,147 @@
1
1
  require 'rails_helper'
2
2
 
3
3
  describe "interaction for <%= controller_class_name %>", type: :feature do
4
- <% unless @auth.nil? %> let(:<%= @auth %>) {create(:<%= @auth.gsub('current_', '') %>)}<%end%>
5
- let(:<%= singular %>) {create(:<%= singular %><%= object_parent_mapping_as_argument_for_specs %> )}
4
+ include HotGlue::ControllerHelper
5
+ <% unless @auth.nil? %>let(:<%= @auth %>) {create(:<%= @auth.gsub('current_', '') %>)}<%end%>
6
6
 
7
- <%= objest_nest_factory_setup %>
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
- before(:each) do
11
+ <%= objest_nest_factory_setup %>
10
12
 
13
+ before(:each) do
14
+ login_as(<%= @auth %>)
11
15
  end
12
16
 
13
17
  describe "index" do
14
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 ")
15
34
 
16
- end
17
35
  end
18
36
 
19
- describe "new" do
20
- it "should show form" do
37
+ }.join("\n")
38
+
39
+ %>
21
40
 
22
41
  end
23
42
  end
24
43
 
25
- describe "create" do
26
- it "should create a new <%= singular %>" do
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 %>")]')
49
+
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
55
+ #
56
+
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
27
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})"
28
81
  end
29
- end
30
82
 
31
- describe "edit" do
32
- it "should return an editable form" do
83
+ }.join("\n")
84
+ %>
33
85
 
34
86
  end
35
87
  end
36
88
 
37
89
  describe "show" do
38
90
  it "should return a view form" do
91
+ visit <%= path_helper_plural %>
39
92
 
40
93
  end
41
94
  end
42
95
 
43
- describe "update" do
44
- it "should update" do
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
100
+
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
45
134
  end
46
135
  end
47
136
 
48
137
  describe "destroy" do
49
138
  it "should destroy" do
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)
50
145
  end
51
146
  end
52
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 %>}
@@ -1,3 +1,3 @@
1
1
  module HotGlue
2
- VERSION = '0.0.9'
2
+ VERSION = '0.1.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hot-glue
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.9
4
+ version: 0.1.0
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-03-24 00:00:00.000000000 Z
11
+ date: 2021-04-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/20210306223305_create_hgis.rb
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
@@ -1,9 +0,0 @@
1
- class CreateHgis < ActiveRecord::Migration[6.1]
2
- def change
3
- create_table :hgis do |t|
4
- t.integer :def_id
5
-
6
- t.timestamps
7
- end
8
- end
9
- end
@@ -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
-