hot-glue 0.6.17 → 0.6.19
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/Gemfile.lock +1 -1
- data/README.md +89 -5
- data/app/helpers/hot_glue/controller_helper.rb +21 -0
- data/lib/generators/hot_glue/fields/association_field.rb +37 -13
- data/lib/generators/hot_glue/fields/boolean_field.rb +6 -6
- data/lib/generators/hot_glue/fields/field.rb +6 -4
- data/lib/generators/hot_glue/fields/integer_field.rb +21 -1
- data/lib/generators/hot_glue/scaffold_generator.rb +46 -13
- data/lib/generators/hot_glue/templates/controller.rb.erb +35 -12
- data/lib/hotglue/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 9e7085c942cab4dc377c75180d546b57f6ca76bdb3c96f3b2a837d1fdd887b0f
|
4
|
+
data.tar.gz: 04fd50131e53977f25c8817c7fd7bd33e34cb0aa784c995394c94302491b1426
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: fa984faeba62c9303c5ae0c64b32143e054289380ffdfecf2f0d457c7b2c2d69912b69901d78ee6fff75f1e6997ed19e86a4cc00a8c048341fbf2505e687a984
|
7
|
+
data.tar.gz: 052122bbbc7d15c134653efc4da2b74df8400447eccae13d395627bd5d79b2a616f612c97ac995f07b563a8589c9609406320562616f7efe637b94d7289a5e8a
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -680,15 +680,49 @@ For the `$` modifier only, if the field name ends with `_cents`, the modifier wi
|
|
680
680
|
|
681
681
|
### `--alt-foreign-key-lookup=`
|
682
682
|
|
683
|
-
Use for a join table to specify that a field should be looked up by a different field
|
683
|
+
Use for a join table to specify that a field should be looked up by a different field. For example, when you want to lookup a user by a (complete) email address.
|
684
684
|
|
685
|
+
In these contexts, the lookup must be exact match to the text entered (no partial matches supported).
|
685
686
|
|
686
|
-
|
687
|
+
Use `+` to map to the `find_or_create_by` method. (Without `+` it will use `find_by`.)
|
688
|
+
|
689
|
+
This is accomlished using a little magic of a lookup field called `__lookup_X_Y` passed in the form parameters.
|
690
|
+
|
691
|
+
The lookup field is used to look up the associated record, then deleted from the params.
|
692
|
+
|
693
|
+
#### When used in `--gd` mode
|
694
|
+
The lookup will use the base class and have access to all records.
|
695
|
+
`user = User.find_or_create_by!(email: params[:__lookup_email])`
|
696
|
+
`modified_params.tap { |hs| hs.delete(:__lookup_target_email)}`
|
697
|
+
`modified_params.merge!(user: user)`
|
698
|
+
|
699
|
+
Example 1
|
700
|
+
`./bin/rails generate hot_glue:scaffold AccountUser --gd --alt-foreign-key-lookup=user_id{email}`
|
687
701
|
|
688
702
|
Here we are specifying that the `user_id` field should be looked up by the `email` field on the User table.
|
689
703
|
If no existing user exists, we create one because we are using the `find_or_create_by!` method.
|
690
704
|
|
705
|
+
### When used with a Hawk
|
706
|
+
|
707
|
+
A hawk applied to the same field will be enforced within this mechanism.
|
708
|
+
|
709
|
+
Example #2
|
710
|
+
`bin/rails generate hot_glue:scaffold Appointment --gd --alt-foreign-key-lookup='user_id{email}' --hawk='user_id{current_user.family}'`
|
711
|
+
|
712
|
+
|
713
|
+
Whether or not in Gd mode, the hawk is enforced by scoping the find to the hawk's scope
|
714
|
+
```
|
715
|
+
user = current_user.family.users.find_by(email: appointment_params[:__lookup_user_email] )
|
716
|
+
modified_params.tap { |hs| hs.delete(:__lookup_user_email)}
|
717
|
+
@appointment = Appointment.new(modified_params.merge(user: user))
|
718
|
+
```
|
719
|
+
|
720
|
+
|
721
|
+
|
722
|
+
### With Factory
|
723
|
+
|
691
724
|
Use with a factory pattern like this one:
|
725
|
+
|
692
726
|
```
|
693
727
|
class AccountUserFactory
|
694
728
|
attr_accessor :account_user
|
@@ -712,9 +746,17 @@ end
|
|
712
746
|
this works with a factory creation syntax like so:
|
713
747
|
|
714
748
|
```
|
715
|
-
--factory-creation='factory = AccountUserFactory.new(params: account_user_params, account: account)
|
749
|
+
rails generate hot_glue:scaffold AccountUser --alt-foreign-key-lookup=user_id{email} --factory-creation='factory = AccountUserFactory.new(params: account_user_params, account: account)
|
716
750
|
```
|
717
|
-
|
751
|
+
|
752
|
+
In this example, the lookup is *not performed inside of the create action*, because it is assumed you will do so yourself inside of your factory.
|
753
|
+
|
754
|
+
As you see in the example above, params is passed to your factory and it is the `account_user_params` fromm the controller.
|
755
|
+
|
756
|
+
#### Warning:
|
757
|
+
When building a non-Gd controller with a `--alt-foreign-key-lookup`, if you don't also hawk the same field you will get an error.
|
758
|
+
|
759
|
+
To fix, either hawk the field or use with a factory creation pattern. This is because the associated object is on your graph but Hot Glue doesn't know how to securly load it without knowing its relationship to the current user. Use the `--hawk` mechanism to specify that relationship, and the lookup mechanism will integrate nicely.
|
718
760
|
|
719
761
|
|
720
762
|
|
@@ -1401,6 +1443,16 @@ If you leave the 2nd parameter blank when using the 3rd parameter, it will defau
|
|
1401
1443
|
|
1402
1444
|
`--attachments='avatar{thumbnail||direct}'`
|
1403
1445
|
|
1446
|
+
#### `--attachments` Long form syntax with 4 parameters
|
1447
|
+
|
1448
|
+
The final (4th) parameter should be `dropzone` to enable dropzone support for this attachment.
|
1449
|
+
|
1450
|
+
```
|
1451
|
+
bin/rails generate hot_glue:scaffold Video --auth='current_user' --auth-identifier='user' --namespace='account_dashboard' --nested='account' --smart-layout --attachments='video_file{thumbnail||direct|dropzone}'
|
1452
|
+
```
|
1453
|
+
|
1454
|
+
See below for dropzone details.
|
1455
|
+
|
1404
1456
|
|
1405
1457
|
#### For S3 Setup
|
1406
1458
|
|
@@ -1902,7 +1954,38 @@ These automatic pickups for partials are detected at build time. This means that
|
|
1902
1954
|
|
1903
1955
|
# VERSION HISTORY
|
1904
1956
|
|
1905
|
-
#### 2025-
|
1957
|
+
#### 2025-06-10 v0.6.19
|
1958
|
+
|
1959
|
+
• Fixes magic button output behavior to correctly show the string returned by the bang menthod
|
1960
|
+
• Fixes internal syntax of modify_as for modified fields; note default is now 'Yes' and 'No' for radio buttons
|
1961
|
+
• fixes destroy behavior with explicit .destroy! and ActiveRecord::RecordNotDestroyed; documents previously undocumented 4th parameter for attachment input
|
1962
|
+
|
1963
|
+
|
1964
|
+
#### 2025-05-18 v0.6.18
|
1965
|
+
• Significant additions to `--alt-foreign-key-lookup` which can now work:
|
1966
|
+
- on its own, without needing a factory (`--factory-creation`)
|
1967
|
+
- with a factory
|
1968
|
+
- with our without the hawk
|
1969
|
+
- in Gd mode
|
1970
|
+
- if not in Gd mode, use with `--factory-creation` or use with the `--hawk`
|
1971
|
+
|
1972
|
+
See notes above for details.
|
1973
|
+
|
1974
|
+
example apps
|
1975
|
+
https://github.com/hot-glue-for-rails/HGHumanSpaMay25
|
1976
|
+
https://github.com/hot-glue-for-rails/HGAltLookups11
|
1977
|
+
|
1978
|
+
|
1979
|
+
• Adds Integer as searchable field
|
1980
|
+
|
1981
|
+
_ foo and bar are integers _
|
1982
|
+
|
1983
|
+
`rails g hot_glue:scaffold Thing --include=foo,bar --search=set --search-fields=foo,bar`
|
1984
|
+
|
1985
|
+
• On show only association fields, view output is now safe-nil using `&` to not crash if the association doesn't exist.
|
1986
|
+
|
1987
|
+
|
1988
|
+
#### 2025-05-09 - v0.6.17
|
1906
1989
|
|
1907
1990
|
|
1908
1991
|
• Adds Stimulus JS & `--stimmify` or `--stimmify=xyz`
|
@@ -1935,6 +2018,7 @@ https://jasonfleetwoodboldt.com/courses/rails-7-crash-course/rails-7-stimulus-js
|
|
1935
2018
|
• Adds `--hidden` option
|
1936
2019
|
Pass a list of fields, like include or show-only. This will make the field hidden on the form *but still updated via its submission*
|
1937
2020
|
|
2021
|
+
• Show only fields associations are now safe-nil using `&` to not crash if the association doesn't exist
|
1938
2022
|
|
1939
2023
|
|
1940
2024
|
|
@@ -143,6 +143,27 @@ module HotGlue
|
|
143
143
|
end
|
144
144
|
end
|
145
145
|
|
146
|
+
def integer_query_constructor(match, search)
|
147
|
+
if match.blank? || search.blank?
|
148
|
+
nil
|
149
|
+
else
|
150
|
+
case match
|
151
|
+
when '='
|
152
|
+
"= #{search.to_i}"
|
153
|
+
when '≥'
|
154
|
+
">= #{search.to_i}"
|
155
|
+
when '>'
|
156
|
+
"> #{search.to_i}"
|
157
|
+
when '≤'
|
158
|
+
"<= #{search.to_i}"
|
159
|
+
when '<'
|
160
|
+
"< #{search.to_i}"
|
161
|
+
else
|
162
|
+
nil
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
146
167
|
def enum_constructor(field_name, value, **args)
|
147
168
|
return nil if value.blank?
|
148
169
|
["#{field_name} = ?", value]
|
@@ -82,25 +82,23 @@ class AssociationField < Field
|
|
82
82
|
display_column = HotGlue.derrive_reference_name(assoc_class_name)
|
83
83
|
|
84
84
|
|
85
|
-
"<%= #{singular}.#{assoc_name}
|
85
|
+
"<%= #{singular}.#{assoc_name}&.#{display_column} %>"
|
86
86
|
end
|
87
87
|
|
88
88
|
def form_field_output
|
89
89
|
assoc_name = name.to_s.gsub("_id","")
|
90
|
+
|
91
|
+
|
90
92
|
assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
|
91
|
-
|
92
|
-
|
93
|
+
|
94
|
+
if alt_lookup.keys.include?(name)
|
93
95
|
assoc_name = name.to_s.gsub("_id","")
|
94
96
|
assoc = eval("#{class_name}.reflect_on_association(:#{assoc_name})")
|
95
97
|
|
96
|
-
|
98
|
+
lookup_field = alt_lookup[name][:lookup_as]
|
99
|
+
assoc = alt_lookup[name][:assoc].downcase
|
97
100
|
parts = name.split('_')
|
98
|
-
"<%= f.text_field :__lookup_#{
|
99
|
-
|
100
|
-
# if modify_as
|
101
|
-
# modified_display_output
|
102
|
-
# else
|
103
|
-
# end
|
101
|
+
"<%= f.text_field :__lookup_#{assoc}_#{lookup_field}, value: @#{singular}.#{assoc_name}&.#{lookup_field}, placeholder: \"#{lookup_field}\" " + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + "%>"
|
104
102
|
elsif modify_as && modify_as[:typeahead]
|
105
103
|
search_url = "#{namespace ? namespace + "_" : ""}" +
|
106
104
|
modify_as[:nested].join("_") + ( modify_as[:nested].any? ? "_" : "") +
|
@@ -150,7 +148,7 @@ class AssociationField < Field
|
|
150
148
|
if @stimmify
|
151
149
|
col_target = HotGlue.to_camel_case(name.to_s.gsub("_", " "))
|
152
150
|
data_attr = ", data: {'#{@stimmify}-target': '#{col_target}'} "
|
153
|
-
|
151
|
+
else
|
154
152
|
data_attr = ""
|
155
153
|
end
|
156
154
|
|
@@ -188,11 +186,9 @@ class AssociationField < Field
|
|
188
186
|
|
189
187
|
if assoc_class
|
190
188
|
display_column = HotGlue.derrive_reference_name(assoc_class.to_s)
|
191
|
-
|
192
189
|
"<%= #{singular}.#{assoc}.try(:#{display_column}) || '<span class=\"content \">MISSING</span>'.html_safe %>"
|
193
190
|
else
|
194
191
|
"<%= #{singular}.#{assoc}.try(:to_label) || '<span class=\"content \">MISSING</span>'.html_safe %>"
|
195
|
-
|
196
192
|
end
|
197
193
|
|
198
194
|
end
|
@@ -274,5 +270,33 @@ class AssociationField < Field
|
|
274
270
|
end
|
275
271
|
end
|
276
272
|
|
273
|
+
def prelookup_syntax
|
274
|
+
field = @alt_lookup[name.to_s]
|
275
|
+
if field[:with_create]
|
276
|
+
|
277
|
+
method_name = "find_or_create_by"
|
277
278
|
|
279
|
+
else
|
280
|
+
method_name = "find_by"
|
281
|
+
end
|
282
|
+
field_name = field[:assoc].downcase.gsub("_id","")
|
283
|
+
assoc_class = field[:assoc].classify
|
284
|
+
|
285
|
+
assoc = plural
|
286
|
+
|
287
|
+
## TODO: add the hawk here
|
288
|
+
res = +""
|
289
|
+
if @hawk_keys[name.to_sym]
|
290
|
+
res << "#{field_name} = #{@hawk_keys[name.to_sym][:bind_to].first}.#{method_name}(#{field[:lookup_as]}: #{singular}_params[:__lookup_#{field[:assoc].downcase}_#{field[:lookup_as]}] )"
|
291
|
+
elsif @god
|
292
|
+
assoc_name = field[:assoc]
|
293
|
+
res << "#{field_name} = #{assoc_class}.#{method_name}(#{field[:lookup_as]}: #{singular}_params[:__lookup_#{field[:assoc].downcase}_#{field[:lookup_as]}] )"
|
294
|
+
else
|
295
|
+
raise "Field #{field_name} is an alt lookup in a non-Gd context which is a security vulnerability"
|
296
|
+
end
|
297
|
+
|
298
|
+
res << "\n modified_params.tap { |hs| hs.delete(:__lookup_#{field[:assoc].downcase}_#{field[:lookup_as]})}"
|
299
|
+
return res
|
300
|
+
|
301
|
+
end
|
278
302
|
end
|
@@ -23,9 +23,9 @@ class BooleanField < Field
|
|
23
23
|
|
24
24
|
def radio_button_display
|
25
25
|
" <%= f.radio_button(:#{name}, '0', checked: #{singular}.#{name} ? '' : 'checked', class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
|
26
|
-
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[
|
26
|
+
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[:binary][:falsy] || 'No'}', for: '#{singular}_#{name}_0') %>\n" +
|
27
27
|
" <br /> <%= f.radio_button(:#{name}, '1', checked: #{singular}.#{name} ? 'checked' : '' , class: '#{@layout_strategy.form_checkbox_input_class}') %>\n" +
|
28
|
-
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[
|
28
|
+
" <%= f.label(:#{name}, value: '#{modify_binary? && modify_as[:binary][:truthy] || 'Yes'}', for: '#{singular}_#{name}_1') %>\n"
|
29
29
|
end
|
30
30
|
|
31
31
|
def checkbox_display
|
@@ -59,9 +59,9 @@ class BooleanField < Field
|
|
59
59
|
"<% if #{singular}.#{name}.nil? %>
|
60
60
|
<span class=''>MISSING</span>
|
61
61
|
<% elsif #{singular}.#{name} %>
|
62
|
-
#{modify_as[
|
62
|
+
#{modify_as[:binary][:truthy]}
|
63
63
|
<% else %>
|
64
|
-
#{modify_as[
|
64
|
+
#{modify_as[:binary][:falsy]}
|
65
65
|
<% end %>"
|
66
66
|
else
|
67
67
|
"<% if #{singular}.#{name}.nil? %>
|
@@ -75,11 +75,11 @@ class BooleanField < Field
|
|
75
75
|
end
|
76
76
|
|
77
77
|
def truthy_value
|
78
|
-
modify_as[
|
78
|
+
modify_as[:binary][:truthy] || 'Yes'
|
79
79
|
end
|
80
80
|
|
81
81
|
def falsy_value
|
82
|
-
modify_as[
|
82
|
+
modify_as[:binary][:falsy] || 'No'
|
83
83
|
end
|
84
84
|
|
85
85
|
def label_class
|
@@ -6,7 +6,7 @@ class Field
|
|
6
6
|
:self_auth,
|
7
7
|
:singular_class, :singular, :sql_type, :ownership_field,
|
8
8
|
:update_show_only, :namespace, :pundit, :plural,
|
9
|
-
:stimmify, :hidden, :attachment_data
|
9
|
+
:stimmify, :hidden, :attachment_data, :god
|
10
10
|
|
11
11
|
|
12
12
|
def initialize(
|
@@ -25,7 +25,7 @@ class Field
|
|
25
25
|
@form_placeholder_labels = scaffold.form_placeholder_labels
|
26
26
|
@ownership_field = scaffold.ownership_field
|
27
27
|
@form_labels_position = scaffold.form_labels_position
|
28
|
-
@modify_as = scaffold.modify_as
|
28
|
+
@modify_as = scaffold.modify_as[name.to_sym] # note whenever used as field, don't relookup the key
|
29
29
|
@display_as = scaffold.display_as
|
30
30
|
@pundit = scaffold.pundit
|
31
31
|
@plural = scaffold.plural
|
@@ -35,6 +35,7 @@ class Field
|
|
35
35
|
@stimmify = scaffold.stimmify
|
36
36
|
@hidden = scaffold.hidden
|
37
37
|
@attachment_data = scaffold.attachments[name.to_sym]
|
38
|
+
@god = scaffold.god
|
38
39
|
|
39
40
|
|
40
41
|
# TODO: remove knowledge of subclasses from Field
|
@@ -112,7 +113,7 @@ class Field
|
|
112
113
|
end
|
113
114
|
|
114
115
|
def viewable_output
|
115
|
-
if modify_as
|
116
|
+
if modify_as
|
116
117
|
modified_display_output(show_only: true)
|
117
118
|
else
|
118
119
|
field_view_output
|
@@ -158,7 +159,6 @@ class Field
|
|
158
159
|
# end
|
159
160
|
# res = "<span class='badge <%= #{badge_code} %>'>" + res + "</span>"
|
160
161
|
# end
|
161
|
-
# byebug
|
162
162
|
res
|
163
163
|
end
|
164
164
|
|
@@ -225,4 +225,6 @@ class Field
|
|
225
225
|
false
|
226
226
|
end
|
227
227
|
|
228
|
+
def prelookup_syntax; nil; end
|
229
|
+
|
228
230
|
end
|
@@ -29,6 +29,26 @@ class IntegerField < Field
|
|
29
29
|
end
|
30
30
|
|
31
31
|
def search_field_output
|
32
|
-
|
32
|
+
" <div>" +
|
33
|
+
"\n <%= f.select 'q[0][#{name}_match]', options_for_select([['', ''], ['=', '='], " +
|
34
|
+
"\n ['≥', '≥'], ['>', '>'], " +
|
35
|
+
"\n ['≤', '≤'], ['<', '<']], @q[\'0\']['#{name}_match'] ), {} ," +
|
36
|
+
"\n { class: 'form-control match' } %>"+
|
37
|
+
"\n <%= f.text_field 'q[0][#{name}_search]', {value: @q[\'0\'][:#{name}_search], autocomplete: 'off', size: 4, class: 'form-control', type: 'number'} %>" +
|
38
|
+
"\n </div>"
|
33
39
|
end
|
40
|
+
|
41
|
+
|
42
|
+
def where_query_statement
|
43
|
+
".where(\"#{name} \#{#{name}_query }\")"
|
44
|
+
end
|
45
|
+
|
46
|
+
def load_all_query_statement
|
47
|
+
"#{name}_query = integer_query_constructor(@q['0'][:#{name}_match], @q['0'][:#{name}_search])"
|
48
|
+
end
|
49
|
+
|
50
|
+
def code_to_reset_match_if_search_is_blank
|
51
|
+
" @q['0'][:#{name}_match] = '' if @q['0'][:#{name}_search] == ''"
|
52
|
+
end
|
53
|
+
|
34
54
|
end
|
@@ -20,7 +20,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
20
20
|
:big_edit, :button_icons, :bootstrap_column_width,
|
21
21
|
:columns,
|
22
22
|
:default_boolean_display,
|
23
|
-
:display_as, :downnest_children, :downnest_object, :hawk_keys, :layout_object,
|
23
|
+
:display_as, :downnest_children, :downnest_object, :god, :hawk_keys, :layout_object,
|
24
24
|
:modify_as,
|
25
25
|
:nest_with, :path, :plural, :sample_file_path, :show_only_data, :singular,
|
26
26
|
:singular_class, :smart_layout, :stacked_downnesting,
|
@@ -84,7 +84,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
84
84
|
|
85
85
|
# determines if labels appear within the rows of the VIEWABLE list (does NOT affect the list heading)
|
86
86
|
class_option :inline_list_labels, default: nil # default is set below
|
87
|
-
class_option :factory_creation, default:
|
87
|
+
class_option :factory_creation, default: nil
|
88
88
|
class_option :alt_foreign_key_lookup, default: '' #
|
89
89
|
class_option :attachments, default: ''
|
90
90
|
class_option :stacked_downnesting, default: false
|
@@ -437,7 +437,6 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
437
437
|
@related_sets = {}
|
438
438
|
related_set_input.each do |setting|
|
439
439
|
name = setting.to_sym
|
440
|
-
byebug
|
441
440
|
association_ids_method = eval("#{singular_class}.reflect_on_association(:#{setting.to_sym})").class_name.underscore + "_ids"
|
442
441
|
class_name = eval("#{singular_class}.reflect_on_association(:#{setting.to_sym})").class_name
|
443
442
|
|
@@ -480,7 +479,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
480
479
|
end
|
481
480
|
end
|
482
481
|
|
483
|
-
|
482
|
+
unless options['factory_creation'].nil?
|
483
|
+
@factory_creation = options['factory_creation'].gsub(";", "\n")
|
484
|
+
end
|
485
|
+
|
484
486
|
identify_object_owner
|
485
487
|
setup_fields
|
486
488
|
|
@@ -506,6 +508,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
506
508
|
setting =~ /(.*){(.*)}/
|
507
509
|
key, lookup_as = $1, $2
|
508
510
|
|
511
|
+
if !eval("#{class_name}.reflect_on_association(:#{key.to_s.gsub("_id","")})")
|
512
|
+
raise "couldn't find association for #{key} in the object #{class_name}"
|
513
|
+
end
|
509
514
|
assoc = eval("#{class_name}.reflect_on_association(:#{key.to_s.gsub("_id","")}).class_name")
|
510
515
|
|
511
516
|
data = {lookup_as: lookup_as.gsub("+",""),
|
@@ -514,7 +519,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
514
519
|
@alt_lookups[key] = data
|
515
520
|
end
|
516
521
|
|
517
|
-
|
522
|
+
|
518
523
|
|
519
524
|
# @update_alt_lookups = @alt_lookups.collect{|key, value|
|
520
525
|
# @update_show_only.include?(key) ?
|
@@ -578,6 +583,18 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
578
583
|
end
|
579
584
|
end
|
580
585
|
|
586
|
+
|
587
|
+
puts "------ ALT LOOKUPS for #{@alt_lookups}"
|
588
|
+
@alt_lookups.each do |key, value|
|
589
|
+
if !@columns_map[key.to_sym].is_a?(AssociationField)
|
590
|
+
raise "You specified an alt-lookup for #{key} but that field is not an association field"
|
591
|
+
elsif !@columns_map[key.to_sym]
|
592
|
+
raise "You specified an alt-lookup for #{key} but that field does not exist in the list of columns"
|
593
|
+
elsif !@god && !@hawk_keys.include?(key.to_sym)
|
594
|
+
raise "You specified an alt-lookup for #{key} in non-Gd mode but this would leave the lookup unprotected. To fix, use with --hawk or with --factory-creation "
|
595
|
+
end
|
596
|
+
end
|
597
|
+
|
581
598
|
# search
|
582
599
|
@search = options['search']
|
583
600
|
if @search == 'set'
|
@@ -677,7 +694,6 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
677
694
|
if options["hawk"]
|
678
695
|
options['hawk'].split(",").each do |hawk_entry|
|
679
696
|
# format is: abc_id[thing]
|
680
|
-
|
681
697
|
if hawk_entry.include?("{")
|
682
698
|
hawk_entry =~ /(.*){(.*)}/
|
683
699
|
key, hawk_to = $1, $2
|
@@ -687,6 +703,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
687
703
|
end
|
688
704
|
|
689
705
|
hawk_scope = key.gsub("_id", "").pluralize
|
706
|
+
|
690
707
|
if eval(singular_class + ".reflect_on_association(:#{key.gsub('_id', '')})").nil?
|
691
708
|
raise "Could not find `#{key.gsub('_id', '')}` association; add this to the #{singular_class} class: \nbelongs_to :#{key.gsub('_id', '')} "
|
692
709
|
end
|
@@ -836,6 +853,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
836
853
|
:confirmation_token, :confirmed_at,
|
837
854
|
:confirmation_sent_at, :unconfirmed_email
|
838
855
|
|
856
|
+
|
857
|
+
# TODO: this should exclude any nested parents
|
839
858
|
@exclude_fields.push(@ownership_field.to_sym) if !@ownership_field.nil?
|
840
859
|
|
841
860
|
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject { |field| @exclude_fields.include?(field) }
|
@@ -844,7 +863,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
844
863
|
@columns = @the_object.columns.map(&:name).map(&:to_sym).reject { |field| !@include_fields.include?(field) }
|
845
864
|
end
|
846
865
|
|
847
|
-
@columns = @columns
|
866
|
+
@columns = @columns - @nested_set.collect { |set| (set[:singular] + "_id").to_sym }
|
848
867
|
|
849
868
|
if @attachments.any?
|
850
869
|
puts "Adding attachments-as-columns: #{@attachments}"
|
@@ -888,8 +907,21 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
888
907
|
end
|
889
908
|
|
890
909
|
def creation_syntax
|
891
|
-
if @factory_creation
|
892
|
-
"@#{singular } = #{ class_name }.new(modified_params)"
|
910
|
+
if @factory_creation.nil? && ! @alt_lookups.any?
|
911
|
+
( @hawk_keys.any? ? "modified_params = hawk_params({#{ hawk_to_ruby }}, modified_params)\n " : "") + "@#{singular } = #{ class_name }.new(modified_params)"
|
912
|
+
elsif @factory_creation.nil? && @alt_lookups.any?
|
913
|
+
|
914
|
+
prelookup_syntax = @alt_lookups.collect{|lookup, data|
|
915
|
+
col = @columns_map[lookup.to_sym]
|
916
|
+
col.prelookup_syntax
|
917
|
+
}.join("\n")
|
918
|
+
|
919
|
+
prelookup_syntax + "\n @#{singular } = #{ class_name }.new(modified_params" +
|
920
|
+
(@alt_lookups.any? ? (".merge(" + @alt_lookups.collect{|lookup,field|
|
921
|
+
field_name = lookup.gsub("_id","")
|
922
|
+
"#{field_name}: #{field_name}"
|
923
|
+
}.join(",") + ")" ) : "") + ")"
|
924
|
+
|
893
925
|
else
|
894
926
|
res = +"begin
|
895
927
|
#{@factory_creation}
|
@@ -954,10 +986,11 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
954
986
|
|
955
987
|
template "system_spec.rb.erb", dest_file
|
956
988
|
end
|
957
|
-
|
958
|
-
|
959
|
-
|
960
|
-
|
989
|
+
# if !File.exist?("#{filepath_prefix}app/views#{namespace_with_dash}/_errors.#{@markup}")
|
990
|
+
# # File.delete("#{filepath_prefix}app/views#{namespace_with_dash}/_errors.#{@markup}")
|
991
|
+
#
|
992
|
+
# template "_errors.erb", File.join("#{filepath_prefix}app/views#{namespace_with_dash}", "_errors.#{@markup}")
|
993
|
+
# end
|
961
994
|
end
|
962
995
|
|
963
996
|
def spec_foreign_association_merge_hash
|
@@ -27,10 +27,12 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
27
27
|
def <%= @nested_set[0][:singular] %><% if @god
|
28
28
|
next_object = nil
|
29
29
|
collect_objects = @nested_set.reverse.collect {|x|
|
30
|
-
if eval("#{next_object || class_name}.reflect_on_association(:#{x[:singular]})").nil?
|
31
|
-
raise "***** Unable to find the association `#{x[:singular]}` on the class #{next_object || class_name} ..... you probably want to add `belongs_to :#{x}` to the #{next_object || class_name} object?"
|
30
|
+
if eval("#{next_object || class_name}.reflect_on_association(:#{x[:singular]})").nil? #&& eval("! #{next_object || class_name}.instance_methods.include?(:#{x[:singular]})")
|
31
|
+
raise "***** Unable to find the association `#{x[:singular]}` on the class #{next_object || class_name} ..... you probably want to add `belongs_to :#{x[:singular]}` to the #{next_object || class_name} object?"
|
32
32
|
end
|
33
|
+
# if eval("#{next_object || class_name}.reflect_on_association(:#{x[:singular]})")
|
33
34
|
next_object = eval("#{next_object || class_name}.reflect_on_association(:#{x[:singular]})").class_name
|
35
|
+
# end
|
34
36
|
}
|
35
37
|
root_object = collect_objects.last
|
36
38
|
else
|
@@ -110,11 +112,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
110
112
|
modified_params = modified_params.merge(<%= @object_owner_sym %>: <%= @object_owner_eval %>) <% elsif @object_owner_optional && any_nested? %>
|
111
113
|
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% end %>
|
112
114
|
|
113
|
-
<% if @hawk_keys.any? %>
|
114
|
-
modified_params = hawk_params({<%= hawk_to_ruby %>}, modified_params)<% end %>
|
115
115
|
<%= controller_attachment_orig_filename_pickup_syntax %>
|
116
116
|
<%= creation_syntax %>
|
117
|
-
|
117
|
+
|
118
|
+
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
118
119
|
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :create)<% end %><% end %>
|
119
120
|
<% if @pundit && !@pundit_policy_override %>
|
120
121
|
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
@@ -185,8 +186,13 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
185
186
|
flash[:alert] = nil
|
186
187
|
<% @magic_buttons.each do |button| %>
|
187
188
|
if <%= singular_name %>_params[:__<%= button %>]
|
188
|
-
|
189
|
-
|
189
|
+
|
190
|
+
if res = @<%= singular_name %>.<%= button %>!
|
191
|
+
flash[:notice] << "<% singular %> <%= button.titlecase %>"
|
192
|
+
flash[:notice] << " #{res}" if res.is_a?(String)
|
193
|
+
else
|
194
|
+
flash[:alert] = " <%= button.titlecase %> failed."
|
195
|
+
end
|
190
196
|
end
|
191
197
|
<% end %>
|
192
198
|
|
@@ -195,8 +201,20 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
195
201
|
modified_params = modified_params.merge(<%= @object_owner_name %> ? {<%= @object_owner_sym %>: <%= @object_owner_eval %>} : {}) <% end %>
|
196
202
|
<% if @pundit %><% @related_sets.each do |key, related_set| %>
|
197
203
|
check_<%= related_set[:association_ids_method].to_s %>_permissions(modified_params, :update)<% end %><% end %>
|
204
|
+
<% if (@alt_lookups.any?) %>
|
205
|
+
<%= @alt_lookups.collect{|lookup, data|
|
206
|
+
@columns_map[lookup.to_sym].prelookup_syntax unless @update_show_only.include?(lookup.to_sym)
|
207
|
+
}.join("\n") %>
|
208
|
+
<% elsif @factory_creation %>
|
198
209
|
|
199
|
-
|
210
|
+
<% end %>
|
211
|
+
<% if (@alt_lookups.keys.collect(&:to_sym) - @update_show_only).any? %>
|
212
|
+
modified_params.merge!(<%= @alt_lookups.collect{|lookup,field|
|
213
|
+
field_name = lookup.gsub("_id","")
|
214
|
+
"#{field_name}: #{field_name}" unless @update_show_only.include?(lookup.to_sym)
|
215
|
+
}.join(",") %>)
|
216
|
+
<% end %>
|
217
|
+
<% if @hawk_keys.any? %> modified_params = hawk_params({<%= hawk_to_ruby %>}, modified_params)<% end %>
|
200
218
|
<%= controller_attachment_orig_filename_pickup_syntax %>
|
201
219
|
<% if @pundit && !@pundit_policy_override %>
|
202
220
|
authorize @<%= singular_name %>
|
@@ -221,6 +239,11 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
221
239
|
<% end %>
|
222
240
|
else
|
223
241
|
flash[:alert] = "<%= singular_name.titlecase %> could not be saved. #{@hawk_alarm}"
|
242
|
+
<%= @alt_lookups.collect{ |k,v|
|
243
|
+
assoc = k.gsub("_id","")
|
244
|
+
"@#{singular }.#{k} = #{class_name}.find(@#{singular }.id).person.id if @#{singular }.errors.include?(:#{assoc})"
|
245
|
+
|
246
|
+
}.join("\n") %>
|
224
247
|
@action = 'edit'
|
225
248
|
<% unless @big_edit %>render :update<% else %>render :edit<% end %>, status: :unprocessable_entity
|
226
249
|
end<% if @pundit %>
|
@@ -236,9 +259,9 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
236
259
|
skip_authorization
|
237
260
|
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.destroy?<% end %>
|
238
261
|
begin
|
239
|
-
@<%=singular_name%>.destroy
|
262
|
+
@<%=singular_name%>.destroy!
|
240
263
|
flash[:notice] = '<%= singular_name.titlecase %> successfully deleted'
|
241
|
-
rescue
|
264
|
+
rescue ActiveRecord::RecordNotDestroyed => e
|
242
265
|
flash[:alert] = '<%= singular_name.titlecase %> could not be deleted'
|
243
266
|
end
|
244
267
|
<%= post_action_parental_updates.join("\n ") %>
|
@@ -261,12 +284,12 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
261
284
|
end<% end %><% end %>
|
262
285
|
|
263
286
|
def <%=singular_name%>_params
|
264
|
-
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? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>)
|
287
|
+
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? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>)
|
265
288
|
end<% if @update_show_only %>
|
266
289
|
|
267
290
|
<% unless @no_edit %>
|
268
291
|
def update_<%=singular_name%>_params
|
269
|
-
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? %>)
|
292
|
+
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? %><%= ", " + @alt_lookups.collect{|k,v| ":__lookup_#{v[:assoc].downcase}_#{v[:lookup_as]}" }.join(", ") if @alt_lookups.any? %>)
|
270
293
|
end<% end %>
|
271
294
|
<% end %>
|
272
295
|
|
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.19
|
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: 2025-
|
11
|
+
date: 2025-06-10 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|