hot-glue 0.6.0 → 0.6.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile.lock +5 -5
- data/README.md +77 -20
- data/lib/generators/hot_glue/field_factory.rb +6 -1
- data/lib/generators/hot_glue/fields/association_field.rb +15 -15
- data/lib/generators/hot_glue/fields/attachment_field.rb +2 -3
- data/lib/generators/hot_glue/fields/field.rb +10 -4
- data/lib/generators/hot_glue/fields/related_set_field.rb +60 -0
- data/lib/generators/hot_glue/markup_templates/erb.rb +4 -3
- data/lib/generators/hot_glue/scaffold_generator.rb +52 -12
- data/lib/generators/hot_glue/templates/controller.rb.erb +28 -9
- data/lib/generators/hot_glue/templates/typeahead_controller.rb.erb +1 -1
- data/lib/generators/hot_glue/templates/typeahead_views/index.html.erb +1 -1
- data/lib/generators/hot_glue/templates/typeahead_views/typeahead_controller.js +7 -1
- data/lib/generators/hot_glue/templates/typeahead_views/typeahead_results_controller.js +0 -2
- data/lib/hotglue/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 98f341b6907ade21c64956cab48b59503280aefaf9836b718d33e26ed854d32a
|
4
|
+
data.tar.gz: ada2f154b32372c90c107c7507cb57d65850e761017bd17c04e6d5afc7302097
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7f38775a9cd7743c6dfb39fe4c4bed6e8b27e6987dd455b460205db6b0e13f8ea5c25e7bd24d59992ead7ca8d689f31fc71c73c5f40ea7578aaace49c41dfaca
|
7
|
+
data.tar.gz: ce1fa03301507fdc462d8a43d6d0253a4bbf8d1c2184d1a582683d56ff67d5d5b9eb21b60902a8d4dfe390d41e4b3ade485e255db659ab7683e34558d838388a
|
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.6.0.1)
|
5
5
|
ffaker (~> 2.16)
|
6
6
|
kaminari (~> 1.2)
|
7
7
|
rails (> 5.1)
|
@@ -90,7 +90,7 @@ GEM
|
|
90
90
|
xpath (~> 3.2)
|
91
91
|
concurrent-ruby (1.1.10)
|
92
92
|
crass (1.0.6)
|
93
|
-
date (3.3.
|
93
|
+
date (3.3.4)
|
94
94
|
devise (4.8.1)
|
95
95
|
bcrypt (~> 3.0)
|
96
96
|
orm_adapter (~> 0.1)
|
@@ -139,12 +139,12 @@ GEM
|
|
139
139
|
mini_mime (1.1.2)
|
140
140
|
mini_portile2 (2.8.4)
|
141
141
|
minitest (5.16.3)
|
142
|
-
net-imap (0.4.
|
142
|
+
net-imap (0.4.4)
|
143
143
|
date
|
144
144
|
net-protocol
|
145
145
|
net-pop (0.1.2)
|
146
146
|
net-protocol
|
147
|
-
net-protocol (0.2.
|
147
|
+
net-protocol (0.2.2)
|
148
148
|
timeout
|
149
149
|
net-smtp (0.4.0)
|
150
150
|
net-protocol
|
@@ -235,7 +235,7 @@ GEM
|
|
235
235
|
stimulus-rails (1.1.1)
|
236
236
|
railties (>= 6.0.0)
|
237
237
|
thor (1.2.1)
|
238
|
-
timeout (0.4.
|
238
|
+
timeout (0.4.1)
|
239
239
|
turbo-rails (1.3.2)
|
240
240
|
actionpack (>= 6.0.0)
|
241
241
|
activejob (>= 6.0.0)
|
data/README.md
CHANGED
@@ -64,25 +64,23 @@ _If you are on Rails 6, see [LEGACY SETUP FOR RAILS 6](https://github.com/jasonf
|
|
64
64
|
|
65
65
|
## The Super-Quick Setup
|
66
66
|
|
67
|
-
https://jasonfleetwoodboldt.com/courses/stepping-up-rails/rails-
|
67
|
+
https://jasonfleetwoodboldt.com/courses/stepping-up-rails/jason-fleetwood-boldts-rails-cookbook/
|
68
68
|
|
69
|
-
Copy & paste the whole code block from each section into your terminal.
|
69
|
+
Copy & paste the whole code block from each section into your terminal. Remember, there is a small "Copy" button at the top-right of each code block to help you copy & paste the script into your terminal.
|
70
70
|
|
71
|
+
These are the sections you need, you can ignore any others:
|
71
72
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
Sectoin #6 is for Hot Glue itself, and Section #7 is for Kaminari
|
83
|
-
|
84
|
-
You will also need section #8 to setup Devise if you want authentication.
|
73
|
+
* Section 1A for a new JS Bundling app, then skip down to
|
74
|
+
* Section 2B: Rspec + Friends
|
75
|
+
* Section 2B-Capy: Capybara for Rspec, then skip down to
|
76
|
+
* Section 3 for a welcome controller
|
77
|
+
( you can skip everything in Section 4 )
|
78
|
+
* Section 5 for debugging tools
|
79
|
+
* _Section 6 is the Hot Glue installer itself_ (this gem) - for Bootstrap, choose section 6A
|
80
|
+
* Section 7A to install Bootstrap along with CSSBundling
|
81
|
+
* Section 8 to set up Devise if you want authentication. (See how Hot Glue interacts with Devise below.)
|
85
82
|
|
83
|
+
If you do this through the quick setup above, you can then skip down past the next section to the "HOT GLUE DOCS" below.
|
86
84
|
|
87
85
|
## Step-By-Step Setup
|
88
86
|
|
@@ -294,10 +292,21 @@ Alternatively, you can define your own driver like so:
|
|
294
292
|
|
295
293
|
# HOT GLUE DOCS
|
296
294
|
|
295
|
+
Remember: Use `bin/rails generate model Thing` to generate models. Then add `has_many`, `belongs_to`, and _migrate your database_ before building the scaffold with Hot Glue.
|
296
|
+
|
297
|
+
You will also need every Rails model to contain _either_ a database column _or_ an object-level method named one of these five things:
|
298
|
+
`name`
|
299
|
+
`to_label`
|
300
|
+
`full_name`
|
301
|
+
`display_name`
|
302
|
+
`email`
|
303
|
+
|
304
|
+
If your database doesn't contain one of these five, add a method to your model using `def to_label`. This will be used as the default label for the object throughout the Hot Glue build system.
|
305
|
+
|
297
306
|
## First Argument
|
298
307
|
(no double slash)
|
299
308
|
|
300
|
-
TitleCase class name of the thing you want to build a
|
309
|
+
TitleCase class name of the thing you want to build a scaffolding for.
|
301
310
|
|
302
311
|
```
|
303
312
|
./bin/rails generate hot_glue:scaffold Thing
|
@@ -672,8 +681,9 @@ Notice that each modifiers can be used with specific field types.
|
|
672
681
|
| (truthy label)\|(falsy label) | specify a binary switch with a pipe (\|) character if the value is truthy, it will display as "truthy label" if the value is falsy, it will display as "falsy label" | booleans, datetimes, dates, times | | |
|
673
682
|
| partials | applies to enums only, you must have a partial whose name matches each enum type | enums only | | |
|
674
683
|
| tinymce | applies to text fields only, be sure to setup TineMCE globally | text fields only | | |
|
684
|
+
| typeahead | turns a foreign key (only) into a searchable typeahead field | foreign keys only | | |
|
675
685
|
|
676
|
-
Except for "(truthy label)" and "(falsy label)" which
|
686
|
+
Except for "(truthy label)" and "(falsy label)" which use the special syntax, use the modifier _exactly_ as it is named.
|
677
687
|
|
678
688
|
### `--pundit`
|
679
689
|
If you enable Pundit, your controllers will look for a Policy that matches the name of the thing being built.
|
@@ -954,6 +964,25 @@ This happens using two interconnected mechanisms:
|
|
954
964
|
please note that *creating* and *deleting* do not yet have a full & complete implementation: Your pages won't re-render the pages being viewed cross-peer (that is, between two users using the app at the same time) if the insertion or deletion causes the pagination to be off for another user.
|
955
965
|
|
956
966
|
|
967
|
+
### `--related-sets`
|
968
|
+
|
969
|
+
Used to show a checkbox set of related records. The relationship should be a `has_and_belongs_to_many` or a `has_many through:` from the object being built.
|
970
|
+
|
971
|
+
Consider the classic example of three tables: users, user_roles, and roles
|
972
|
+
|
973
|
+
User `has_many :user_roles`; UserRole `belongs_to :user` and `belongs_to :role`; and Role `has_many :user_roles` and `has_many :user, through: :user_roles`
|
974
|
+
|
975
|
+
We'll generate a scaffold to edit the users table. A checkbox set of related roles will also appear to allow editing of roles. (In this example, the only field to be edited is the email field.)
|
976
|
+
|
977
|
+
```
|
978
|
+
rails generate hot_glue:scaffold User --related-sets=roles --include=email,roles --gd
|
979
|
+
```
|
980
|
+
|
981
|
+
Note this leaves open a privileged escalation attack (a security vulnerability).
|
982
|
+
|
983
|
+
To fix this, you'll need to use Pundit with special syntax designed for this purpose. Please see Example #16 in the [https://school.jfbcodes.com/8188](Hot Glue Tutorial).
|
984
|
+
|
985
|
+
|
957
986
|
## "Thing" Label
|
958
987
|
|
959
988
|
Note that on a per model basis, you can also globally omit the label or set a unique label value using
|
@@ -1393,11 +1422,11 @@ You can now use a typeahead when editing the book. Instead of displaying the aut
|
|
1393
1422
|
You will do these three things:
|
1394
1423
|
|
1395
1424
|
1. As a one-time setup step for your app, run
|
1396
|
-
`bin/rails generate hot_glue:
|
1425
|
+
`bin/rails generate hot_glue:typeahead_install`
|
1397
1426
|
2. When generating a scaffold you want to make a typeahead association, use `--modify='parent_id{typeahead}'` where `parent_id` is the foreign key
|
1398
1427
|
`bin/rails generate hot_glue:scaffold Book --include=title,author_id --modify='author_id{typeahead}'`
|
1399
1428
|
3. Within each namespace, you will generate a special typeahead controller (it exists for the associated object to be searched on
|
1400
|
-
`bin/rails generate hot_glue:
|
1429
|
+
`bin/rails generate hot_glue:typeahead Author`
|
1401
1430
|
This will create a controller for `AuthorsTypeaheadController` that will allow text search against any *string* field on the `Author` model.
|
1402
1431
|
This special generator takes flags `--namespace` as the normal generator and also `--search-by` to let you specify the list of fields you want to search by.
|
1403
1432
|
|
@@ -1464,6 +1493,34 @@ bin/rails generate Thing --include=my_story --modify='my_story{tinymce}'
|
|
1464
1493
|
|
1465
1494
|
# VERSION HISTORY
|
1466
1495
|
|
1496
|
+
#### v0.6.1 - `--related-sets`
|
1497
|
+
|
1498
|
+
Used to show a checkbox set of related records. The relationship should be a `has_and_belongs_to_many` or a `has_many through:` from the object being built.
|
1499
|
+
|
1500
|
+
Consider the classic example of three tables: users, user_roles, and roles
|
1501
|
+
|
1502
|
+
User `has_many :user_roles`; UserRole `belongs_to :user` and `belongs_to :role`; and Role `has_many :user_roles` and `has_many :user, through: :user_roles`
|
1503
|
+
|
1504
|
+
We'll generate a scaffold to edit the users table. A checkbox set of related roles will also appear to allow editing of roles. (In this example, the only field to be edited is the email field.)
|
1505
|
+
|
1506
|
+
```
|
1507
|
+
rails generate hot_glue:scaffold User --related-sets=roles --include=email,roles --gd
|
1508
|
+
```
|
1509
|
+
|
1510
|
+
Note that when making a scaffold like this, you may leave open a privileged escalation attack (a security vulnerability).
|
1511
|
+
|
1512
|
+
To fix this, you'll need to use Pundit with special syntax designed for this purpose.
|
1513
|
+
|
1514
|
+
For a complete solution, please see Example #16 in the [https://school.jfbcodes.com/8188](Hot Glue Tutorial).
|
1515
|
+
|
1516
|
+
Without Pundit, due to a quirk in how this code works with ActiveRecord, all update operates to the related sets table are permitted (and go through), even if the update operation otherwise fails validation for the fields on the object. (ActiveRecord doesn't seem to have a way to validate the related sets directly.)
|
1517
|
+
|
1518
|
+
In this case, your update actions may update the relate sets table but fail to update the current object.
|
1519
|
+
|
1520
|
+
Using this feature with Pundit will fix this problem, and it is achieved with a (hacky) implementation that performs a pre-check for each related set against the Pundit policy.
|
1521
|
+
|
1522
|
+
#### v0.6.0.1 - small tweaks to typeahead
|
1523
|
+
|
1467
1524
|
#### 2023-11-03 - v0.6.0
|
1468
1525
|
|
1469
1526
|
Typeahead Associations
|
@@ -1476,7 +1533,7 @@ from a searchable typehead input.
|
|
1476
1533
|
The typeahead is implemented with a native Stimulus JS pair of controllers and is a modern & clean replacement to the old typeahead options.
|
1477
1534
|
|
1478
1535
|
1. As a one-time setup step for your app, run
|
1479
|
-
`bin/rails generate hot_glue:
|
1536
|
+
`bin/rails generate hot_glue:typeahead_install`
|
1480
1537
|
2. When generating a scaffold you want to make a typeahead association, use `--modify='parent_id{typeahead}'` where `parent_id` is the foreign key
|
1481
1538
|
`bin/rails generate hot_glue:scaffold Book --include=title,author_id --modify='author_id{typeahead}'`
|
1482
1539
|
3. Within each namespace, you will generate a special typeahead controller (it exists for the associated object to be searched on
|
@@ -10,6 +10,8 @@ require_relative "fields/text_field"
|
|
10
10
|
require_relative "fields/time_field"
|
11
11
|
require_relative "fields/uuid_field"
|
12
12
|
require_relative "fields/attachment_field"
|
13
|
+
require_relative "fields/related_set_field"
|
14
|
+
|
13
15
|
|
14
16
|
|
15
17
|
class FieldFactory
|
@@ -42,6 +44,8 @@ class FieldFactory
|
|
42
44
|
EnumField
|
43
45
|
when :attachment
|
44
46
|
AttachmentField
|
47
|
+
when :related_set
|
48
|
+
RelatedSetField
|
45
49
|
end
|
46
50
|
@class_name = class_name
|
47
51
|
|
@@ -61,6 +65,7 @@ class FieldFactory
|
|
61
65
|
modify_as: generator.modify_as[name.to_sym] || nil,
|
62
66
|
display_as: generator.display_as[name.to_sym] || nil,
|
63
67
|
default_boolean_display: generator.default_boolean_display,
|
64
|
-
namespace: generator.namespace_value
|
68
|
+
namespace: generator.namespace_value,
|
69
|
+
pundit: generator.pundit )
|
65
70
|
end
|
66
71
|
end
|
@@ -10,7 +10,7 @@ class AssociationField < Field
|
|
10
10
|
update_show_only: ,
|
11
11
|
hawk_keys: , auth: , sample_file_path:, ownership_field: ,
|
12
12
|
attachment_data: nil , layout_strategy: , form_placeholder_labels: nil,
|
13
|
-
form_labels_position:, modify_as: , self_auth: , namespace:
|
13
|
+
form_labels_position:, modify_as: , self_auth: , namespace:, pundit: )
|
14
14
|
super
|
15
15
|
|
16
16
|
@assoc_model = eval("#{class_name}.reflect_on_association(:#{assoc})")
|
@@ -80,20 +80,20 @@ class AssociationField < Field
|
|
80
80
|
assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
|
81
81
|
|
82
82
|
if modify_as && modify_as[:typeahead]
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
83
|
+
search_url = "#{namespace ? namespace + "_" : ""}#{assoc.plural_name}_typeahead_index_url"
|
84
|
+
"<div class='typeahead typeahead--#{assoc.name}_id'
|
85
|
+
data-controller='typeahead'
|
86
|
+
data-typeahead-url-value='<%= #{search_url} %>'
|
87
|
+
data-typeahead-typeahead-results-outlet='#search-results'>
|
88
|
+
<%= text_field_tag :#{assoc.plural_name}_query, '', placeholder: 'Search #{assoc.plural_name}', class: 'search__input',
|
89
|
+
data: { action: 'keyup->typeahead#fetchResults keydown->typeahead#navigateResults', typeahead_target: 'query' },
|
90
|
+
autofocus: true,
|
91
|
+
autocomplete: 'off',
|
92
|
+
value: #{singular}.try(:#{assoc.name}).try(:name) %>
|
93
|
+
<%= f.hidden_field :#{assoc.name}_id, value: #{singular}.try(:#{assoc.name}).try(:id), 'data-typeahead-target': 'hiddenFormValue' %>
|
94
|
+
<div data-typeahead-target='results'></div>
|
95
|
+
<div data-typeahead-target='classIdentifier' data-id=\"typeahead--#{assoc_name}_id\"></div>
|
96
|
+
</div>"
|
97
97
|
else
|
98
98
|
if assoc.nil?
|
99
99
|
exit_message = "*** Oops. on the #{class_name} object, there doesn't seem to be an association called '#{assoc_name}'"
|
@@ -1,10 +1,9 @@
|
|
1
1
|
class AttachmentField < Field
|
2
2
|
attr_accessor :attachment_data
|
3
3
|
def initialize(name:, class_name:, default_boolean_display: ,
|
4
|
-
display_as:,
|
5
|
-
singular:, update_show_only:, hawk_keys:, auth:,
|
4
|
+
display_as:, singular:, update_show_only:, hawk_keys:, auth:,
|
6
5
|
sample_file_path: nil, attachment_data:, ownership_field:, layout_strategy: ,
|
7
|
-
form_placeholder_labels: , form_labels_position:, modify_as:, self_auth: , namespace:
|
6
|
+
form_placeholder_labels: , form_labels_position:, modify_as:, self_auth: , namespace:, pundit: )
|
8
7
|
super
|
9
8
|
|
10
9
|
@attachment_data = attachment_data
|
@@ -5,7 +5,7 @@ class Field
|
|
5
5
|
:hawk_keys, :layout_strategy, :limit, :modify_as, :name, :object, :sample_file_path,
|
6
6
|
:self_auth,
|
7
7
|
:singular_class, :singular, :sql_type, :ownership_field,
|
8
|
-
:update_show_only, :namespace
|
8
|
+
:update_show_only, :namespace, :pundit
|
9
9
|
|
10
10
|
def initialize(
|
11
11
|
auth: ,
|
@@ -24,7 +24,8 @@ class Field
|
|
24
24
|
singular: ,
|
25
25
|
update_show_only:,
|
26
26
|
self_auth:,
|
27
|
-
namespace
|
27
|
+
namespace:,
|
28
|
+
pundit:
|
28
29
|
)
|
29
30
|
@name = name
|
30
31
|
@layout_strategy = layout_strategy
|
@@ -40,13 +41,14 @@ class Field
|
|
40
41
|
@form_labels_position = form_labels_position
|
41
42
|
@modify_as = modify_as
|
42
43
|
@display_as = display_as
|
44
|
+
@pundit = pundit
|
43
45
|
|
44
46
|
@self_auth = self_auth
|
45
47
|
@default_boolean_display = default_boolean_display
|
46
|
-
@
|
48
|
+
@namespace = namespace
|
47
49
|
|
48
50
|
# TODO: remove knowledge of subclasses from Field
|
49
|
-
unless self.class == AttachmentField
|
51
|
+
unless self.class == AttachmentField || self.class == RelatedSetField
|
50
52
|
@sql_type = eval("#{class_name}.columns_hash['#{name}']").sql_type
|
51
53
|
@limit = eval("#{class_name}.columns_hash['#{name}']").limit
|
52
54
|
end
|
@@ -56,6 +58,10 @@ class Field
|
|
56
58
|
@name
|
57
59
|
end
|
58
60
|
|
61
|
+
def form_field_output
|
62
|
+
raise "superclass must implement"
|
63
|
+
end
|
64
|
+
|
59
65
|
def field_error_name
|
60
66
|
name
|
61
67
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
class RelatedSetField < Field
|
2
|
+
|
3
|
+
attr_accessor :assoc_name, :assoc_class, :assoc
|
4
|
+
|
5
|
+
def initialize( class_name: , default_boolean_display:, display_as: ,
|
6
|
+
name: , singular: ,
|
7
|
+
update_show_only: ,
|
8
|
+
hawk_keys: , auth: , sample_file_path:, ownership_field: ,
|
9
|
+
attachment_data: nil , layout_strategy: , form_placeholder_labels: nil,
|
10
|
+
form_labels_position:, modify_as: , self_auth: , namespace:, pundit:)
|
11
|
+
super
|
12
|
+
|
13
|
+
@related_set_model = eval("#{class_name}.reflect_on_association(:#{name})")
|
14
|
+
|
15
|
+
if @related_set_model.nil?
|
16
|
+
raise "You specified a related set #{name} but there is no association on #{singular_class} for #{name}; please add a `has_and_belongs_to_many :#{name}` OR a `has_many :#{name}, through: ...` to the #{singular_class} model"
|
17
|
+
|
18
|
+
# exit_message = "*** Oops: The model #{class_name} is missing an association for :#{assoc_name} or the model #{assoc_name.titlecase} doesn't exist. TODO: Please implement a model for #{assoc_name.titlecase}; or add to #{class_name} `belongs_to :#{assoc_name}`. To make a controller that can read all records, specify with --god."
|
19
|
+
puts exit_message
|
20
|
+
raise(HotGlue::Error, exit_message)
|
21
|
+
end
|
22
|
+
|
23
|
+
@assoc_class = eval(@related_set_model.try(:class_name))
|
24
|
+
|
25
|
+
name_list = [:name, :to_label, :full_name, :display_name, :email]
|
26
|
+
|
27
|
+
if assoc_class && name_list.collect{ |field|
|
28
|
+
assoc_class.respond_to?(field.to_s) || assoc_class.instance_methods.include?(field)
|
29
|
+
}.none?
|
30
|
+
exit_message = "Oops: Missing a label for `#{assoc_class}`. Can't find any column to use as the display label for the #{@assoc_name} association on the #{class_name} model. TODO: Please implement just one of: 1) name, 2) to_label, 3) full_name, 4) display_name 5) email. You can implement any of these directly on your`#{assoc_class}` model (can be database fields or model methods) or alias them to field you want to use as your display label. Then RERUN THIS GENERATOR. (Field used will be chosen based on rank here.)"
|
31
|
+
raise(HotGlue::Error, exit_message)
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
def form_field_output
|
38
|
+
disabled_syntax = +""
|
39
|
+
if pundit
|
40
|
+
disabled_syntax << ", {disabled: ! #{class_name}Policy.new(#{auth}, @#{singular}).role_ids_able?}"
|
41
|
+
end
|
42
|
+
" <%= f.collection_check_boxes :#{association_ids_method}, #{association_class_name}.all, :id, :label, {}#{disabled_syntax} do |m| %>
|
43
|
+
<%= m.check_box %> <%= m.label %><br />
|
44
|
+
<% end %>"
|
45
|
+
end
|
46
|
+
|
47
|
+
def association_ids_method
|
48
|
+
eval("#{class_name}.reflect_on_association(:#{name})").class_name.underscore + "_ids"
|
49
|
+
end
|
50
|
+
|
51
|
+
def association_class_name
|
52
|
+
eval("#{class_name}.reflect_on_association(:#{name})").class_name
|
53
|
+
end
|
54
|
+
|
55
|
+
def viewable_output
|
56
|
+
"<%= #{singular}.#{name}.collect(&:label).join(\", \") %>"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
|
@@ -8,7 +8,7 @@ module HotGlue
|
|
8
8
|
:inline_list_labels, :layout_object,
|
9
9
|
:columns, :col_identifier, :singular,
|
10
10
|
:form_placeholder_labels, :hawk_keys, :update_show_only,
|
11
|
-
:attachments, :show_only, :columns_map, :pundit
|
11
|
+
:attachments, :show_only, :columns_map, :pundit, :related_sets
|
12
12
|
|
13
13
|
|
14
14
|
def initialize(singular:, singular_class: ,
|
@@ -17,7 +17,7 @@ module HotGlue
|
|
17
17
|
ownership_field: , form_labels_position: ,
|
18
18
|
inline_list_labels: ,
|
19
19
|
form_placeholder_labels:, hawk_keys: ,
|
20
|
-
update_show_only:, attachments: , columns_map:, pundit:
|
20
|
+
update_show_only:, attachments: , columns_map:, pundit:, related_sets: )
|
21
21
|
|
22
22
|
@singular = singular
|
23
23
|
@singular_class = singular_class
|
@@ -39,6 +39,7 @@ module HotGlue
|
|
39
39
|
@hawk_keys = hawk_keys
|
40
40
|
@update_show_only = update_show_only
|
41
41
|
@attachments = attachments
|
42
|
+
@related_sets = related_sets
|
42
43
|
end
|
43
44
|
|
44
45
|
def add_spaces_each_line(text, num_spaces)
|
@@ -150,7 +151,7 @@ module HotGlue
|
|
150
151
|
|
151
152
|
"<div class='#{col_identifier} #{singular}--#{column.join("-")}'#{style_with_flex_basis}> " +
|
152
153
|
column.map { |col|
|
153
|
-
if eval("#{singular_class}.columns_hash['#{col}']").nil? && !attachments.keys.include?(col)
|
154
|
+
if eval("#{singular_class}.columns_hash['#{col}']").nil? && !attachments.keys.include?(col) && !related_sets.include?(col)
|
154
155
|
raise "Can't find column '#{col}' on #{singular_class}, are you sure that is the column name?"
|
155
156
|
end
|
156
157
|
field_output = columns_map[col].line_field_output
|
@@ -23,7 +23,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
23
23
|
:nest_with, :path, :plural, :sample_file_path, :show_only_data, :singular,
|
24
24
|
:singular_class, :smart_layout, :stacked_downnesting, :update_show_only, :ownership_field,
|
25
25
|
:layout_strategy, :form_placeholder_labels, :form_labels_position, :pundit,
|
26
|
-
:self_auth, :namespace_value
|
26
|
+
:self_auth, :namespace_value, :related_sets
|
27
27
|
# important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
|
28
28
|
# so we use namespace_value instead
|
29
29
|
|
@@ -89,6 +89,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
89
89
|
class_option :modify, default: {}
|
90
90
|
class_option :display_as, default: {}
|
91
91
|
class_option :pundit, default: nil
|
92
|
+
class_option :related_sets, default: ''
|
92
93
|
|
93
94
|
def initialize(*meta_args)
|
94
95
|
super
|
@@ -320,7 +321,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
320
321
|
end
|
321
322
|
|
322
323
|
if @god
|
323
|
-
@auth = nil
|
324
|
+
# @auth = nil
|
324
325
|
end
|
325
326
|
# when in self auth, the object is the same as the authenticated object
|
326
327
|
|
@@ -370,6 +371,24 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
370
371
|
puts "NESTING: #{@nested_set}"
|
371
372
|
end
|
372
373
|
|
374
|
+
# related_sets
|
375
|
+
related_set_input = options['related_sets'].split(",")
|
376
|
+
@related_sets = {}
|
377
|
+
related_set_input.each do |setting|
|
378
|
+
name = setting.to_sym
|
379
|
+
association_ids_method = eval("#{singular_class}.reflect_on_association(:#{setting.to_sym})").class_name.underscore + "_ids"
|
380
|
+
class_name = eval("#{singular_class}.reflect_on_association(:#{setting.to_sym})").class_name
|
381
|
+
|
382
|
+
@related_sets[setting.to_sym] = { name: setting.to_sym,
|
383
|
+
association_ids_method: association_ids_method,
|
384
|
+
class_name: class_name }
|
385
|
+
end
|
386
|
+
|
387
|
+
if @related_sets.any?
|
388
|
+
puts "RELATED SETS: #{@related_sets}"
|
389
|
+
|
390
|
+
end
|
391
|
+
|
373
392
|
# OBJECT OWNERSHIP & NESTING
|
374
393
|
@reference_name = HotGlue.derrive_reference_name(singular_class)
|
375
394
|
if @auth && @self_auth
|
@@ -409,13 +428,16 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
409
428
|
|
410
429
|
buttons_width = ((!@no_edit && 1) || 0) + ((!@no_delete && 1) || 0) + @magic_buttons.count
|
411
430
|
|
431
|
+
|
432
|
+
|
433
|
+
|
412
434
|
# build a new polymorphic object
|
413
435
|
@associations = []
|
414
436
|
@columns_map = {}
|
415
437
|
@columns.each do |col|
|
416
|
-
if !(@the_object.columns_hash.keys.include?(col.to_s) || @attachments.keys.include?(col))
|
417
|
-
|
418
|
-
end
|
438
|
+
# if !(@the_object.columns_hash.keys.include?(col.to_s) || @attachments.keys.include?(col))
|
439
|
+
# raise "couldn't find #{col} in either field list or attachments list"
|
440
|
+
# end
|
419
441
|
|
420
442
|
if col.to_s.starts_with?("_")
|
421
443
|
@show_only << col
|
@@ -425,6 +447,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
425
447
|
type = @the_object.columns_hash[col.to_s].type
|
426
448
|
elsif @attachments.keys.include?(col)
|
427
449
|
type = :attachment
|
450
|
+
elsif @related_sets.keys.include?(col)
|
451
|
+
type = :related_set
|
452
|
+
else
|
453
|
+
raise "couldn't find #{col} in either field list, attachments, or related sets"
|
428
454
|
end
|
429
455
|
this_column_object = FieldFactory.new(name: col.to_s,
|
430
456
|
generator: self,
|
@@ -440,7 +466,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
440
466
|
if field.is_a?(AssociationField)
|
441
467
|
if @modify_as && @modify_as[key] && @modify_as[key][:typeahead]
|
442
468
|
assoc_name = field.assoc_name
|
443
|
-
file_path = "app/controllers/#{namespace ?
|
469
|
+
file_path = "app/controllers/#{@namespace ? @namespace + "/" : ""}#{assoc_name.pluralize}_typeahead_controller.rb"
|
444
470
|
|
445
471
|
if ! File.exist?(file_path)
|
446
472
|
|
@@ -455,6 +481,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
455
481
|
end
|
456
482
|
end
|
457
483
|
|
484
|
+
|
485
|
+
|
458
486
|
# create the template object
|
459
487
|
if @markup == "erb"
|
460
488
|
@template_builder = HotGlue::ErbTemplate.new(
|
@@ -473,6 +501,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
473
501
|
attachments: @attachments,
|
474
502
|
columns_map: @columns_map,
|
475
503
|
pundit: @pundit,
|
504
|
+
related_sets: @related_sets
|
476
505
|
)
|
477
506
|
elsif @markup == "slim"
|
478
507
|
raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
|
@@ -607,6 +636,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
607
636
|
end
|
608
637
|
|
609
638
|
def identify_object_owner
|
639
|
+
return if @god
|
610
640
|
auth_assoc = @auth && @auth.gsub("current_", "")
|
611
641
|
|
612
642
|
if @object_owner_sym && !@self_auth
|
@@ -657,6 +687,16 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
657
687
|
|
658
688
|
check_if_sample_file_is_present
|
659
689
|
end
|
690
|
+
|
691
|
+
if @related_sets.any?
|
692
|
+
if !@pundit
|
693
|
+
puts "********************\nWARNING: You are using --related-sets without using Pundit. This makes the set fully accessible. Use Pundit to prevent a privileged escalation vulnerability\n********************\n"
|
694
|
+
end
|
695
|
+
@related_sets.each do |key, related_set|
|
696
|
+
@columns << related_set[:name] if !@columns.include?(related_set[:name])
|
697
|
+
puts "Adding related set :#{related_set[:name]} as-a-column"
|
698
|
+
end
|
699
|
+
end
|
660
700
|
end
|
661
701
|
|
662
702
|
def check_if_sample_file_is_present
|
@@ -676,13 +716,13 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
676
716
|
puts ""
|
677
717
|
end
|
678
718
|
|
679
|
-
def
|
680
|
-
@columns
|
719
|
+
def fields_filtered_for_strong_params
|
720
|
+
@columns - @related_sets.collect{|key, set| set[:name]}
|
681
721
|
end
|
682
722
|
|
683
723
|
def creation_syntax
|
684
724
|
if @factory_creation == ''
|
685
|
-
"@#{singular } = #{ class_name }.
|
725
|
+
"@#{singular } = #{ class_name }.new(modified_params)"
|
686
726
|
else
|
687
727
|
"#{@factory_creation}\n" +
|
688
728
|
" @#{singular } = factory.#{singular}"
|
@@ -969,7 +1009,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
969
1009
|
end
|
970
1010
|
|
971
1011
|
def object_scope
|
972
|
-
if @auth
|
1012
|
+
if @auth && !@god
|
973
1013
|
if @nested_set.none?
|
974
1014
|
@auth + ".#{plural}"
|
975
1015
|
else
|
@@ -1296,7 +1336,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1296
1336
|
|
1297
1337
|
def n_plus_one_includes
|
1298
1338
|
if @associations.any? || @attachments.any?
|
1299
|
-
".includes(" + (@associations.map { |x| x } + @attachments.collect { |k, v| "#{k}_attachment" }).map { |x| ":#{x.to_s}" }.join(", ") + ")"
|
1339
|
+
".includes(" + (@associations.map { |x| x } + @attachments.collect { |k, v| "#{k}_attachment" } ).map { |x| ":#{x.to_s}" }.join(", ") + ")"
|
1300
1340
|
else
|
1301
1341
|
""
|
1302
1342
|
end
|
@@ -1342,7 +1382,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
1342
1382
|
end
|
1343
1383
|
|
1344
1384
|
def any_datetime_fields?
|
1345
|
-
(@columns - @attachments.keys.collect(&:to_sym)).collect { |col| eval("#{singular_class}.columns_hash['#{col}']").type }.include?(:datetime)
|
1385
|
+
(@columns - @attachments.keys.collect(&:to_sym) - @related_sets.keys ).collect { |col| eval("#{singular_class}.columns_hash['#{col}']").type }.include?(:datetime)
|
1346
1386
|
end
|
1347
1387
|
|
1348
1388
|
def post_action_parental_updates
|
@@ -72,7 +72,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
72
72
|
|
73
73
|
<% end %>def load_all_<%= plural %><% if @pundit %>
|
74
74
|
@<%= plural_name %> = policy_scope(<%= object_scope %>).page(params[:page])<%= n_plus_one_includes %><%= ".per(per)" if @paginate_per_page_selector %>
|
75
|
-
|
75
|
+
<% else %> <% if !@self_auth %>
|
76
76
|
@<%= plural_name %> = <%= object_scope.gsub("@",'') %><%= n_plus_one_includes %>.page(params[:page])<%= ".per(per)" if @paginate_per_page_selector %><%= " if params.include?(:#{ @nested_set.last[:singular]}_id)" if @nested_set.any? && @nested_set[0] && @nested_set[0][:optional] %><% if @nested_set[0] && @nested_set[0][:optional] %>
|
77
77
|
@<%= plural_name %> = <%= class_name %>.all<% end %><% else %>
|
78
78
|
@<%= plural_name %> = <%= class_name %>.where(id: <%= auth_object.gsub("@",'') %>.id)<%= n_plus_one_includes %>.page(params[:page])<%= ".per(per)" if @paginate_per_page_selector %><% end %>
|
@@ -80,7 +80,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
80
80
|
end
|
81
81
|
|
82
82
|
def index
|
83
|
-
load_all_<%= plural %><% if @pundit %>
|
83
|
+
load_all_<%= plural %><% if @pundit %><% if @pundit %>
|
84
|
+
authorize @<%= plural_name %><% end %>
|
84
85
|
rescue Pundit::NotAuthorizedError
|
85
86
|
flash[:alert] = "You are not authorized to perform this action."
|
86
87
|
render "layouts/error"<% end %>
|
@@ -94,19 +95,23 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
94
95
|
@action = "new"
|
95
96
|
rescue Pundit::NotAuthorizedError
|
96
97
|
flash[:alert] = "You are not authorized to perform this action."
|
98
|
+
load_all_users
|
97
99
|
render :index<% end %>
|
98
100
|
end
|
99
101
|
|
100
102
|
def create
|
101
103
|
modified_params = modify_date_inputs_on_params(<%= singular_name %>_params.dup, <%= current_user_object %>, <%= datetime_fields_list %>) <% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
|
102
104
|
modified_params = modified_params.merge(<%= @object_owner_sym %>: <%= @object_owner_eval %>) <% elsif @object_owner_optional && any_nested? %>
|
103
|
-
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% elsif !@object_owner_eval.empty? %>
|
105
|
+
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% elsif !@object_owner_eval.empty? && !@god %>
|
104
106
|
modified_params = modified_params.merge(<%= @object_owner_eval %>) <% end %>
|
105
107
|
|
106
108
|
<% if @hawk_keys.any? %>
|
107
109
|
modified_params = hawk_params({<%= hawk_to_ruby %>}, modified_params)<% end %>
|
108
|
-
|
110
|
+
<%= controller_attachment_orig_filename_pickup_syntax %>
|
109
111
|
<%= creation_syntax %>
|
112
|
+
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
113
|
+
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :create)<% end %><% end %>
|
114
|
+
<% if @pundit %>authorize @<%= singular %><% end %>
|
110
115
|
|
111
116
|
if @<%= singular_name %>.save
|
112
117
|
flash[:notice] = "Successfully created #{@<%= singular %>.<%= display_class %>}"
|
@@ -152,17 +157,20 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
152
157
|
flash[:notice] << "<% singular %> <%= button.titlecase %>."
|
153
158
|
end
|
154
159
|
<% end %>
|
160
|
+
|
155
161
|
modified_params = modify_date_inputs_on_params(<% if @update_show_only %>update_<% end %><%= singular_name %>_params.dup<%= controller_update_params_tap_away_magic_buttons %>, <%= current_user_object %>, <%= datetime_fields_list %>) <% if @object_owner_sym && eval("#{class_name}.reflect_on_association(:#{@object_owner_sym})").class == ActiveRecord::Reflection::BelongsToReflection %>
|
156
162
|
modified_params = modified_params.merge(<%= @object_owner_sym %>: <%= @object_owner_eval %>) <% elsif @object_owner_optional && any_nested? %>
|
157
|
-
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% elsif ! @object_owner_eval.empty? && !@self_auth%>
|
163
|
+
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% elsif ! @object_owner_eval.empty? && !@self_auth && ! @god%>
|
158
164
|
modified_params = modified_params.merge(<%= @object_owner_eval %>) <% end %>
|
165
|
+
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
166
|
+
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :update)<% end %><% end %>
|
159
167
|
|
160
168
|
<% if @hawk_keys.any? %> modified_params = hawk_params({<%= hawk_to_ruby %>}, modified_params)<% end %>
|
161
169
|
<%= controller_attachment_orig_filename_pickup_syntax %>
|
162
170
|
<% if @pundit %>
|
163
171
|
if @<%= singular_name %>.attributes = modified_params
|
164
|
-
|
165
|
-
|
172
|
+
authorize @<%= singular_name %>
|
173
|
+
@<%= singular_name %>.save
|
166
174
|
<% else %>
|
167
175
|
if @<%= singular_name %>.update(modified_params)
|
168
176
|
<% end %>
|
@@ -194,12 +202,23 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
194
202
|
render :update<% end %>
|
195
203
|
end<% end %>
|
196
204
|
|
205
|
+
<% if @pundit %><% @related_sets.each do |key, rs| %>
|
206
|
+
def check_<%= rs[:association_ids_method] %>_permissions(modified_params, action)
|
207
|
+
if modified_params[:<%= rs[:association_ids_method] %>].present? && modified_params[:<%= rs[:association_ids_method] %>] != @<%= singular %>.<%= rs[:association_ids_method] %>
|
208
|
+
# authorize the <%= rs[:association_ids_method] %> change using special modified_relations: {<%= rs[:association_ids_method] %>: modified_params[:<%= rs[:association_ids_method] %>>]} syntax for Pundit
|
209
|
+
if ! <%= singular_class %>Policy.new(current_user, @<%= singular %>, modified_relations: {role_ids: modified_params[:<%= rs[:association_ids_method] %>]}).method("#{action}?".to_sym).call
|
210
|
+
authorize @<%= singular %>, "#{action}?".to_sym
|
211
|
+
raise Pundit::NotAuthorizedError, message: @<%= singular %>.errors.collect{|k| "#{k.attribute} #{k.message}"}.join(" ")
|
212
|
+
end
|
213
|
+
end
|
214
|
+
end<% end %><% end %>
|
215
|
+
|
197
216
|
def <%=singular_name%>_params
|
198
|
-
params.require(:<%= testing_name %>).permit(<%= (
|
217
|
+
params.require(:<%= testing_name %>).permit(<%= ((fields_filtered_for_strong_params - @show_only ) + @magic_buttons.collect{|x| "__#{x}"}).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "#{rs[:association_ids_method]}: []"}.join(", ") if @related_sets.any? %>)
|
199
218
|
end<% if @update_show_only %>
|
200
219
|
|
201
220
|
def update_<%=singular_name%>_params
|
202
|
-
params.require(:<%= testing_name %>).permit(<%= (
|
221
|
+
params.require(:<%= testing_name %>).permit(<%= ((fields_filtered_for_strong_params - @update_show_only) + @magic_buttons.collect{|x| "__#{x}"}).collect{|sym| ":#{sym}"}.join(", ") %><%= ", " + @related_sets.collect{|key, rs| "#{rs[:association_ids_method]}: []"}.join(", ") if @related_sets.any? %>)
|
203
222
|
end<% end %>
|
204
223
|
|
205
224
|
def namespace
|
@@ -6,7 +6,7 @@ class <%= ((@namespace.titleize.gsub(" ", "") + "::" if @namespace) || "") + @pl
|
|
6
6
|
|
7
7
|
def index
|
8
8
|
query = params[:query]
|
9
|
-
|
9
|
+
@typeahead_identifier = params[:typeahead_identifier]
|
10
10
|
@<%= @plural %> = <%= @singular.titleize.gsub(" ", "") %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
|
11
11
|
|
12
12
|
render layout: false
|
@@ -1,7 +1,7 @@
|
|
1
1
|
|
2
2
|
<div class="typeahead-results__<%= @plural %>"
|
3
3
|
data-controller="typeahead-results"
|
4
|
-
data-typeahead-results-typeahead-outlet="
|
4
|
+
data-typeahead-results-typeahead-outlet=".<\%= @typeahead_identifier %>"
|
5
5
|
data-typeahead-results-current-class="search__result--current" >
|
6
6
|
<ul class="search__results" data-typeahead-results-target="result">
|
7
7
|
<\% if @<%= @plural %>.any? %>
|
@@ -1,7 +1,8 @@
|
|
1
1
|
import { Controller } from "@hotwired/stimulus"
|
2
2
|
|
3
3
|
export default class extends Controller {
|
4
|
-
static targets = [ "query", "results", "hiddenFormValue"
|
4
|
+
static targets = [ "query", "results", "hiddenFormValue",
|
5
|
+
"classIdentifier"]
|
5
6
|
static values = { url: String }
|
6
7
|
static outlets = [ "typeahead-results" ]
|
7
8
|
|
@@ -10,6 +11,10 @@ export default class extends Controller {
|
|
10
11
|
}
|
11
12
|
|
12
13
|
fetchResults() {
|
14
|
+
|
15
|
+
|
16
|
+
var typeaheadIdentifier = this.classIdentifierTarget.dataset.id
|
17
|
+
|
13
18
|
if(this.query == "") {
|
14
19
|
this.reset()
|
15
20
|
return
|
@@ -22,6 +27,7 @@ export default class extends Controller {
|
|
22
27
|
|
23
28
|
const url = new URL(this.urlValue)
|
24
29
|
url.searchParams.append("query", this.query)
|
30
|
+
url.searchParams.append("typeahead_identifier", typeaheadIdentifier)
|
25
31
|
|
26
32
|
this.abortPreviousFetchRequest()
|
27
33
|
|
@@ -12,7 +12,6 @@ export default class extends Controller {
|
|
12
12
|
|
13
13
|
connect() {
|
14
14
|
this.currentResultIndex = 0
|
15
|
-
|
16
15
|
const allElements = this.resultTarget.querySelectorAll(".search-result-item");
|
17
16
|
|
18
17
|
allElements.forEach((element, index) => {
|
@@ -29,7 +28,6 @@ export default class extends Controller {
|
|
29
28
|
const result_id = element.dataset.id;
|
30
29
|
|
31
30
|
// how to pass this to the search controller, set the field value and clear out the search
|
32
|
-
console.log("search item clicked...", result_value, result_id)
|
33
31
|
|
34
32
|
this.typeaheadOutlets.forEach(outlet => {
|
35
33
|
outlet.hiddenFormValueTarget.value = result_id;
|
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.6.
|
4
|
+
version: 0.6.1
|
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: 2023-11-
|
11
|
+
date: 2023-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -90,6 +90,7 @@ files:
|
|
90
90
|
- lib/generators/hot_glue/fields/field.rb
|
91
91
|
- lib/generators/hot_glue/fields/float_field.rb
|
92
92
|
- lib/generators/hot_glue/fields/integer_field.rb
|
93
|
+
- lib/generators/hot_glue/fields/related_set_field.rb
|
93
94
|
- lib/generators/hot_glue/fields/string_field.rb
|
94
95
|
- lib/generators/hot_glue/fields/text_field.rb
|
95
96
|
- lib/generators/hot_glue/fields/time_field.rb
|
@@ -174,5 +175,5 @@ requirements: []
|
|
174
175
|
rubygems_version: 3.4.10
|
175
176
|
signing_key:
|
176
177
|
specification_version: 4
|
177
|
-
summary: A gem to build
|
178
|
+
summary: A gem to build Turbo Rails scaffolding.
|
178
179
|
test_files: []
|