hot-glue 0.6.10 → 0.6.12

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: e97635a9b4a9f05502eaec8834622f0eca2bcf6a984b32819aa92b1f94afebce
4
- data.tar.gz: 05c5ca3e88a7d2fe2e0dce9f22824ae817a3d909f03f8c4a8053bd6d12b72632
3
+ metadata.gz: 1eacfaf1cc09c6a40597a8a0f3f2bda37e156f5ed63be68ff842de01a707dc5d
4
+ data.tar.gz: 20b3c4134a1443c2c5d134a5f5bcdecfb2e13c749c856a1620ecb43209245e68
5
5
  SHA512:
6
- metadata.gz: 47afa457097e68f69f7aaa85d07f8ebe70d47f052875eb52863796122846e9b8993d13e678e8eb927ce44a0331b2a56972a189d8af0e1c4272bd2b2661837548
7
- data.tar.gz: 525847e13f04fec313576a235d864fa2a59781d448bd4a94ed2425d0c2bbb508efd83f0b97d37a9f9f5ab5af7f49b5d9e6dc3797648e5ab39bf7b67823794ef8
6
+ metadata.gz: 3c38593db0539b7259b05b3d3e86062f550d54f969c9a30ad9e2ffa035513c035e154a02ed3f9427def36a025929d0679b66ff0423fc7fdf4ae01623ffb2f540
7
+ data.tar.gz: 6c661dff1800dc911b23681622992fe4e7ac5d554c107e32aa5577f94250022bfbd07be78d33b9c6acab4149aacc2e2ce1047b8f5fd3f728c49139f1db07a4c2
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- hot-glue (0.6.10)
4
+ hot-glue (0.6.12)
5
5
  ffaker (~> 2.16)
6
6
  kaminari (~> 1.2)
7
7
  rails (> 5.1)
@@ -76,6 +76,7 @@ GEM
76
76
  tzinfo (~> 2.0)
77
77
  addressable (2.8.1)
78
78
  public_suffix (>= 2.0.2, < 6.0)
79
+ base64 (0.2.0)
79
80
  bcrypt (3.1.18)
80
81
  builder (3.2.4)
81
82
  byebug (11.1.3)
@@ -139,7 +140,7 @@ GEM
139
140
  mini_mime (1.1.2)
140
141
  mini_portile2 (2.8.4)
141
142
  minitest (5.16.3)
142
- net-imap (0.5.4)
143
+ net-imap (0.5.5)
143
144
  date
144
145
  net-protocol
145
146
  net-pop (0.1.2)
@@ -245,7 +246,8 @@ GEM
245
246
  warden (1.2.9)
246
247
  rack (>= 2.0.9)
247
248
  websocket (1.2.9)
248
- websocket-driver (0.7.6)
249
+ websocket-driver (0.7.7)
250
+ base64
249
251
  websocket-extensions (>= 0.1.0)
250
252
  websocket-extensions (0.1.5)
251
253
  xpath (3.2.0)
data/README.md CHANGED
@@ -987,6 +987,13 @@ Omits controller.
987
987
 
988
988
  Omits list views.
989
989
 
990
+ `--new-button-position` (above, below; default: above)
991
+ Show the new button above or below the list.
992
+
993
+ `--downnest-shows-headings` (default: false)
994
+ Show headings above downnested portals.
995
+
996
+
990
997
  ### `--big-edit`
991
998
 
992
999
  If you do not want inline editing of your list items but instead want to fallback to full-page style behavior for your edit views, use `--big-edit`.
@@ -1106,7 +1113,16 @@ Use `before` to make the labels come before or `after` to make them come after.
1106
1113
 
1107
1114
  Omits the heading of column names that appears above the 1st row of data.
1108
1115
 
1116
+ ### `--include-object-names`
1117
+
1118
+ When you are "Editing X" we specify that X is a ___ (author, book, room, etc)
1109
1119
 
1120
+ e.g. "Editing author Edgar Allan Poe" vs "Editing Edgar Allan Poe"
1121
+
1122
+ Can also be specified globally in `config/hot_glue.yml`
1123
+
1124
+
1125
+ ### Code insertions
1110
1126
 
1111
1127
  `--code-before-create`
1112
1128
  `--code-after-create`
@@ -1585,6 +1601,76 @@ puts the value into the search box and the id into a hidden field.
1585
1601
 
1586
1602
  You need to making a selection *and* click "Save" to update the record.
1587
1603
 
1604
+ The typeahead itself can be both namespaced and nested. (Remember, all controllers are generated at the namespace.)
1605
+
1606
+ Pay close attention to a nested typeahead: When generating the typeahead scaffold use both `--namespace=aaa` and `--nested=bbb/ccc`
1607
+
1608
+ In this example, the typeahead controller will operate at a namespace of `aaa` with two parents: `bbb` and `ccc`
1609
+
1610
+ Combined with `--auth-identifier`, you can load only objects that are related from the `ccc` thing that gets loaded off the `bbb` thing that gets loaded off the current_user.
1611
+
1612
+ This scopes the list returned by the typeahead.
1613
+
1614
+ You need to specify this twice: Once when specifying the typehead scaffold, and also any place in a regular scaffold that uses typeahead:
1615
+
1616
+ For example, assuming we have a reciprocal has_many through for Accounts & Users
1617
+
1618
+ user.rb
1619
+ ```
1620
+ has_many :account_users
1621
+ has_many :accounts, through: :account_users
1622
+ ```
1623
+
1624
+
1625
+ account.rb
1626
+ ```
1627
+ has_many :account_users
1628
+ has_many :users, through: :account_users
1629
+ ```
1630
+
1631
+
1632
+ `bin/rails generate hot_glue:scaffold Member --auth='current_user' --auth-identifier='user' --auth-identifier=user --modify='user_id{typeahead}[account]'`
1633
+
1634
+ in our routes.rb file, we have
1635
+ ```
1636
+ namespace :account_dashboard do
1637
+ resources :accounts do
1638
+ resources :users_typeahead
1639
+ resources :rooms do
1640
+ resources :members
1641
+ end
1642
+ end
1643
+ end
1644
+ ```
1645
+
1646
+ Notice that the scaffold with the references to users is 2 levels deep: accounts -> rooms -> members (and is also in a namespace)
1647
+
1648
+ Notice also that the *users typeahead* operates only one level deep in the same namespace.
1649
+
1650
+ This means that to find users within the search, the essential piece of information is the account, because we want to scope the result set to the users belong to that account.
1651
+
1652
+ • The account must belong to the current_user (notice the account uses nested account provided by the route)
1653
+ • Any users found by the typeahead must belong to the account
1654
+
1655
+ ```
1656
+ def account
1657
+ @account ||= current_user.accounts.find(params[:account_id])
1658
+ end
1659
+
1660
+ def index
1661
+ authorize User, :typeahead?
1662
+ query = params[:query]
1663
+ @typeahead_identifier = params[:typeahead_identifier]
1664
+ @users = account.users.where("LOWER(email) LIKE ? ", "%#{query.downcase}%").limit(10)
1665
+ render layout: false
1666
+ end
1667
+ ```
1668
+
1669
+
1670
+
1671
+ --
1672
+
1673
+
1588
1674
  ### TinyMCE
1589
1675
  1. `bundle add tinymce-rails` to add it to your Gemfile
1590
1676
 
@@ -1658,11 +1744,52 @@ If you have a partial in your view folder called `_list_after_each_row_heading`,
1658
1744
 
1659
1745
  The `within` partials should do operations within the form (like hidden fields), and the `after` partials should do entirely unrelated operations, like a different form entirely.
1660
1746
 
1661
- These automatic pickups for partials are detected at buildtime. This means that if you add these partials later, you must rebuild your scaffold.
1747
+ These automatic pickups for partials are detected at build time. This means that if you add these partials later, you must rebuild your scaffold.
1662
1748
 
1663
1749
 
1664
1750
  # VERSION HISTORY
1665
1751
 
1752
+ #### 2025-02-19 - v0.6.12
1753
+ • adds decimal field type (displays as float-- there is no special handling for decimal on the UI)
1754
+ • guard against polymorphic belongs_to -- not a full implementation for polymorphic fields, just hides the fields on the form; on the list uses to_label always
1755
+ • fixes heading with multiword names on downnested portals to display nicely capitalized
1756
+ • removes open struct
1757
+
1758
+ #### 2025-01-28 v0.6.11
1759
+
1760
+ • Typeahead now can use --auth, --auth-identifier, --namespace, and --nested
1761
+ • Works similar to how same flags work on scaffold generator. (Notice that the typeahead generator is a completely separate generator).
1762
+ • When using nested, your results are scoped the parent objects in the nest chain (which is the last one)
1763
+
1764
+ e.g.
1765
+ `bin/rails generate hot_glue:scaffold Member --auth='current_user' --auth-identifier='user' --auth-identifier=user --modify='user_id{typeahead}[account]'`
1766
+
1767
+ here the user_id field on members will use a typeahead that is built in the namespace `account_dashboard` under 1 parent: `account`
1768
+
1769
+ This would be used in conjunction with a typeahead built using the same namespace and nesting that matches:
1770
+
1771
+ ```
1772
+ bin/rails generate hot_glue:typeahead User --namespace='account_dashboard' --nested='account' --auth-identifier='user' --auth='current_user'
1773
+ ```
1774
+
1775
+ (See 'typeahead' section for details)
1776
+
1777
+ `--include-object-names`
1778
+
1779
+ When you are "Editing X" we specify that X is a ___ (author, book, room, etc)
1780
+
1781
+ e.g. "Editing author Edgar Allan Poe" vs "Editing Edgar Allan Poe"
1782
+
1783
+ Can also be specified globally in `config/hot_glue.yml`
1784
+
1785
+
1786
+ `--new-button-position` (above, below; default: above)
1787
+ Show the new button above or below the list.
1788
+
1789
+ `--downnest-shows-headings` (default: false)
1790
+ Show headings above downnested portals.
1791
+
1792
+
1666
1793
  #### 2024-12-25 v0.6.10
1667
1794
  • adds `--no-nav-menu` option to supress writing to the _nav template
1668
1795
  • the _nav template itself can now end with either .html.erb or .erb
@@ -1,10 +1,13 @@
1
1
  module HotGlueHelper
2
-
3
-
2
+ class KVObject
3
+ attr_accessor :key, :value
4
+ def initialize(key: , value: )
5
+ @key = key
6
+ @value = value
7
+ end
8
+ end
4
9
 
5
10
  def enum_to_collection_select(hash)
6
- hash.collect{|k,v| OpenStruct.new({key: k, value: v})}
7
-
11
+ hash.collect{|k,v| KVObject.new(key: k, value: v)}
8
12
  end
9
-
10
13
  end
@@ -32,6 +32,8 @@ class FieldFactory
32
32
  TextField
33
33
  when :float
34
34
  FloatField
35
+ when :decimal
36
+ FloatField
35
37
  when :datetime
36
38
  DateTimeField
37
39
  when :date
@@ -24,17 +24,18 @@ class AssociationField < Field
24
24
  raise(HotGlue::Error, exit_message)
25
25
  end
26
26
 
27
- @assoc_class = eval(assoc_model.try(:class_name))
27
+ if ! eval("#{class_name}.reflect_on_association(:#{assoc}).polymorphic?")
28
+ @assoc_class = eval(assoc_model.try(:class_name))
28
29
 
29
- name_list = [:name, :to_label, :full_name, :display_name, :email]
30
+ name_list = [:name, :to_label, :full_name, :display_name, :email]
30
31
 
31
- if assoc_class && name_list.collect{ |field|
32
- assoc_class.respond_to?(field.to_s) || assoc_class.instance_methods.include?(field)
33
- }.none?
34
- 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.)"
35
- raise(HotGlue::Error, exit_message)
32
+ if assoc_class && name_list.collect{ |field|
33
+ assoc_class.respond_to?(field.to_s) || assoc_class.instance_methods.include?(field)
34
+ }.none?
35
+ 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.)"
36
+ raise(HotGlue::Error, exit_message)
37
+ end
36
38
  end
37
-
38
39
  end
39
40
 
40
41
  def assoc_label
@@ -110,7 +111,15 @@ class AssociationField < Field
110
111
  # else
111
112
  # end
112
113
  elsif modify_as && modify_as[:typeahead]
113
- search_url = "#{namespace ? namespace + "_" : ""}#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
114
+ search_url = "#{namespace ? namespace + "_" : ""}" +
115
+ modify_as[:nested].join("_") + ("_" if modify_as[:nested].any?) +
116
+ + "#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
117
+
118
+
119
+ if @modify_as[:nested].any?
120
+ search_url << "(" + modify_as[:nested].collect{|x| "#{x}"}.join(",") + ")"
121
+ end
122
+
114
123
  "<div class='typeahead typeahead--#{assoc.name}_id'
115
124
  data-controller='typeahead'
116
125
  data-typeahead-url-value='<%= #{search_url} %>'
@@ -132,7 +141,12 @@ class AssociationField < Field
132
141
 
133
142
  is_owner = name == ownership_field
134
143
  assoc_class_name = assoc.class_name.to_s
135
- display_column = HotGlue.derrive_reference_name(assoc_class_name)
144
+ if assoc_class
145
+ display_column = HotGlue.derrive_reference_name(assoc_class_name)
146
+ else
147
+ # polymorphic
148
+ display_column = "name"
149
+ end
136
150
 
137
151
  if hawk_keys[assoc.foreign_key.to_sym]
138
152
  hawk_definition = hawk_keys[assoc.foreign_key.to_sym]
@@ -170,9 +184,16 @@ class AssociationField < Field
170
184
 
171
185
  def line_field_output
172
186
 
173
- display_column = HotGlue.derrive_reference_name(assoc_class.to_s)
174
187
 
175
- "<%= #{singular}.#{assoc}.try(:#{display_column}) || '<span class=\"content \">MISSING</span>'.html_safe %>"
188
+ if assoc_class
189
+ display_column = HotGlue.derrive_reference_name(assoc_class.to_s)
190
+
191
+ "<%= #{singular}.#{assoc}.try(:#{display_column}) || '<span class=\"content \">MISSING</span>'.html_safe %>"
192
+ else
193
+ "<%= #{singular}.#{assoc}.try(:to_label) || '<span class=\"content \">MISSING</span>'.html_safe %>"
194
+
195
+ end
196
+
176
197
  end
177
198
 
178
199
 
@@ -40,19 +40,18 @@ class BooleanField < Field
40
40
  if display_boolean_as.nil?
41
41
 
42
42
  end
43
- "<div class='#{@layout_strategy.form_checkbox_wrapper_class} #{'form-switch' if display_boolean_as == 'switch'}'>\n" +
43
+ "<span class='#{@layout_strategy.form_checkbox_wrapper_class} #{'form-switch' if display_boolean_as == 'switch'}'>\n" +
44
44
  (if display_boolean_as == 'radio'
45
45
  radio_button_display
46
46
  elsif display_boolean_as == 'checkbox'
47
47
  checkbox_display
48
48
  elsif display_boolean_as == 'switch'
49
49
  switch_display
50
- end) + "</div> \n"
50
+ end) + "</span> \n"
51
51
  end
52
52
 
53
53
  def form_field_output
54
- (form_labels_position == 'before' ? " <br />" : "") +
55
- form_field_display + (form_labels_position == 'after' ? " <br />" : "")
54
+ form_field_display
56
55
  end
57
56
 
58
57
  def line_field_output
@@ -40,7 +40,7 @@ class DateTimeField < Field
40
40
  end
41
41
 
42
42
  def form_field_output
43
- "<%= f.datetime_field( :#{name}, value: #{singular}.#{name} && #{singular}.#{name}.change(sec: 0), class: '#{@layout_strategy.form_input_class}' ) %>"
43
+ "<%= f.datetime_field( :#{name}, value: #{singular}.#{name} && #{singular}.#{name}.in_time_zone(current_timezone), class: '#{@layout_strategy.form_input_class}' ) %><%= current_timezone %>"
44
44
  end
45
45
 
46
46
  def viewable_output
@@ -3,7 +3,7 @@ class RelatedSetField < Field
3
3
  attr_accessor :assoc_name, :assoc_class, :assoc
4
4
 
5
5
  def initialize( class_name: , default_boolean_display:, display_as: ,
6
- name: , singular: ,
6
+ name: , singular: , plural:,
7
7
  alt_lookup: ,
8
8
  update_show_only: ,
9
9
  hawk_keys: , auth: , sample_file_path:, ownership_field: ,
@@ -156,18 +156,20 @@ module HotGlue
156
156
  "<% if @action == 'new' && policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
157
157
 
158
158
  # show only on the update action overrides any pundit policy
159
- elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
160
- "<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
161
- else
162
- columns_map[col].form_field_output
163
- end
159
+ elsif @pundit && eval("defined? #{singular_class}Policy") && eval("#{singular_class}Policy").instance_methods.include?("#{col}_able?".to_sym)
160
+ "<% if policy(@#{singular}).#{col}_able? %>" + columns_map[col].form_field_output + "<% else %>" + columns_map[col].form_show_only_output + "<% end %>"
161
+ else
162
+ columns_map[col].form_field_output
163
+ end
164
+
164
165
 
165
166
  @tinymce_stimulus_controller = (columns_map[col].modify_as == {tinymce: 1} ? "data-controller='tiny-mce' " : "")
167
+
166
168
  add_spaces_each_line( "\n <span #{@tinymce_stimulus_controller}class='<%= \"alert alert-danger\" if #{singular}.errors.details.keys.include?(:#{field_error_name}) %>' #{'style="display: inherit;"'} >\n" +
167
- add_spaces_each_line( (form_labels_position == 'before' ? the_label || "" : "") +
168
- + " <br />\n" + field_result +
169
- (form_labels_position == 'after' ? the_label : "") , 4) +
170
- "\n </span>\n <br />", 2)
169
+ add_spaces_each_line( (form_labels_position == 'before' ? (the_label || "") + "<br />\n" : "") +
170
+ + field_result +
171
+ (form_labels_position == 'after' ? "<br />\n" + (the_label || "") : "") , 4) +
172
+ "\n </span>\n ", 2)
171
173
 
172
174
  }.join("") + "\n </div>"
173
175
  }.join("\n")
@@ -28,7 +28,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
28
28
  :layout_strategy, :form_placeholder_labels,
29
29
  :form_labels_position, :no_nav_menu, :pundit,
30
30
  :self_auth, :namespace_value, :record_scope, :related_sets,
31
- :search_clear_button, :search_autosearch
31
+ :search_clear_button, :search_autosearch, :include_object_names
32
32
  # important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
33
33
  # so we use namespace_value instead
34
34
 
@@ -81,7 +81,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
81
81
  class_option :form_placeholder_labels, type: :boolean, default: false # puts the field names into the placeholder labels
82
82
 
83
83
  # determines if labels appear within the rows of the VIEWABLE list (does NOT affect the list heading)
84
- class_option :inline_list_labels, default: 'omit' # choices are before, after, omit
84
+ class_option :inline_list_labels, default: nil # default is set below
85
85
  class_option :factory_creation, default: ''
86
86
  class_option :alt_foreign_key_lookup, default: '' #
87
87
  class_option :attachments, default: ''
@@ -98,7 +98,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
98
98
  class_option :code_after_update, default: nil
99
99
  class_option :record_scope, default: nil
100
100
  class_option :no_nav_menu, type: :boolean, default: false # suppress writing to _nav template
101
-
101
+ class_option :include_object_names, type: :boolean, default: false
102
+ class_option :new_button_position, type: :string, default: 'above'
103
+ class_option :downnest_shows_headings, type: :boolean, default: nil
102
104
 
103
105
 
104
106
  # SEARCH OPTIONS
@@ -260,7 +262,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
260
262
  elsif $2 == "tinymce"
261
263
  @modify_as[key.to_sym] = {tinymce: 1, badges: $3}
262
264
  elsif $2 == "typeahead"
263
- @modify_as[key.to_sym] = {typeahead: 1, badges: $3}
265
+ if !$3.nil?
266
+ nested = $3.split("/")
267
+ else
268
+ nested = []
269
+ end
270
+ @modify_as[key.to_sym] = {typeahead: 1, nested: nested}
264
271
  elsif $2 == "timezone"
265
272
  @modify_as[key.to_sym] = {timezone: 1, badges: $3}
266
273
  elsif $2 == "none"
@@ -300,7 +307,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
300
307
 
301
308
  setup_hawk_keys
302
309
  @form_placeholder_labels = options['form_placeholder_labels'] # true or false
303
- @inline_list_labels = options['inline_list_labels'] || 'omit' # 'before','after','omit'
310
+ @inline_list_labels = options['inline_list_labels'] || get_default_from_config(key: :inline_list_labels) || 'omit' # 'before','after','omit'
304
311
 
305
312
  @form_labels_position = options['form_labels_position']
306
313
  if !['before', 'after', 'omit'].include?(@form_labels_position)
@@ -337,6 +344,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
337
344
 
338
345
  @smart_layout = options['smart_layout']
339
346
  @record_scope = options['record_scope']
347
+ @downnest_shows_headings = options['downnest_shows_headings']
348
+ @new_button_position = options['new_button_position']
349
+
340
350
 
341
351
  @pundit = options['pundit']
342
352
 
@@ -361,6 +371,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
361
371
  @downnest_object = HotGlue.construct_downnest_object(@downnest)
362
372
  end
363
373
 
374
+ @include_object_names = options['include_object_names'] || get_default_from_config(key: :include_object_names)
375
+
376
+
377
+
364
378
  if @god
365
379
  # @auth = nil
366
380
  end
@@ -463,6 +477,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
463
477
  identify_object_owner
464
478
  setup_fields
465
479
 
480
+
466
481
  if (@columns - @show_only - (@ownership_field ? [@ownership_field.to_sym] : [])).empty?
467
482
  @no_field_form = true
468
483
  end
@@ -1069,7 +1084,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1069
1084
  HotGlue.optionalized_ternary(namespace: @namespace,
1070
1085
  target: @controller_build_folder,
1071
1086
  nested_set: @nested_set,
1072
- with_params: true,
1087
+ with_params: false,
1073
1088
  top_level: false)
1074
1089
  end
1075
1090
 
@@ -1077,7 +1092,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1077
1092
  HotGlue.optionalized_ternary(namespace: @namespace,
1078
1093
  target: @singular,
1079
1094
  nested_set: @nested_set,
1080
- with_params: true,
1095
+ with_params: false,
1081
1096
  put_form: true,
1082
1097
  top_level: false)
1083
1098
  end
@@ -1086,7 +1101,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1086
1101
  HotGlue.optionalized_ternary(namespace: @namespace,
1087
1102
  target: @singular,
1088
1103
  nested_set: @nested_set,
1089
- with_params: true,
1104
+ with_params: false,
1090
1105
  put_form: true)
1091
1106
  end
1092
1107
 
@@ -1095,7 +1110,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1095
1110
  target: @singular,
1096
1111
  nested_set: @nested_set,
1097
1112
  modifier: "edit_",
1098
- with_params: true,
1113
+ with_params: false,
1099
1114
  put_form: true)
1100
1115
  end
1101
1116
 
@@ -1124,7 +1139,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1124
1139
  target: singular,
1125
1140
  nested_set: @nested_set,
1126
1141
  modifier: "new_",
1127
- with_params: true)
1142
+ with_params: false)
1128
1143
  end
1129
1144
 
1130
1145
  def nested_assignments
@@ -1222,7 +1237,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1222
1237
  path: HotGlue.optionalized_ternary( namespace: @namespace,
1223
1238
  target: @singular,
1224
1239
  nested_set: @nested_set,
1225
- with_params: true,
1240
+ with_params: false,
1226
1241
  put_form: true),
1227
1242
  big_edit: @big_edit,
1228
1243
  singular: singular,
@@ -72,13 +72,14 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
72
72
  params[:per] || 10
73
73
  end<% end %>
74
74
  <% unless @no_list %>
75
- def load_all_<%= plural %>
75
+ def load_all_<%= plural %><% if @search == "set" %>
76
+ @q = params[:q] || <%= {"0" => @search_fields.collect{|foo| {"#{foo}_match".to_sym => ((@columns_map[foo.to_sym].modify_as && @columns_map[foo.to_sym].modify_as[:binary]) ? "-1" : ""), "#{foo}_search".to_sym => ""}}.reduce({}, :merge) } %> <% end %>
76
77
  <%= load_all_code %>
77
78
  end
78
79
 
79
- def index<% if @search == "set" %>
80
- @q = params[:q] || <%= {"0" => @search_fields.collect{|foo|
81
- {"#{foo}_match".to_sym => ((@columns_map[foo.to_sym].modify_as && @columns_map[foo.to_sym].modify_as[:binary]) ? "-1" : ""), "#{foo}_search".to_sym => ""}}.reduce({}, :merge) } %> <% end %><% if @search_fields %>
80
+ def index
81
+ load_all_<%= plural %>
82
+ <% if @search_fields %>
82
83
  <%= @search_fields.collect{|field_name| @columns_map[field_name.to_sym].code_to_reset_match_if_search_is_blank}.compact.join(" \n") %><% end %>
83
84
  load_all_<%= plural %><% if @pundit %><% if @pundit %>
84
85
  authorize @<%= plural_name %><% end %>
@@ -131,8 +132,18 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
131
132
  <% unless @display_edit_after_create %>render :create, status: :unprocessable_entity<% else %>render :new , status: :unprocessable_entity<% end %>
132
133
  end<% if @pundit %>
133
134
  rescue Pundit::NotAuthorizedError => e
135
+ flash[:alert] = "Not authorized."
134
136
  @<%= singular %>.errors.add(:base, e.message)
135
- render :create, status: :unprocessable_entity<% end %>
137
+ <% unless @display_edit_after_create %>render :create, status: :unprocessable_entity<% else %>redirect_to <%= HotGlue.optionalized_ternary(namespace: @namespace,
138
+ top_level: true,
139
+ target: @singular,
140
+ nested_set: @nested_set,
141
+ modifier: 'edit_',
142
+ with_params: true,
143
+ instance_last_item: true,
144
+ put_form: true).gsub("(#{singular}", "(@#{singular}") %><% end %>
145
+
146
+ <% end %>
136
147
  end
137
148
 
138
149
  <% end %>
@@ -154,7 +165,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
154
165
  @action = 'edit'
155
166
  render :edit<% if @pundit %>
156
167
  rescue Pundit::NotAuthorizedError
157
- flash[:notice] = "Editing #{@<%= singular %>.<%= display_class %>} not authorized."
168
+ flash[:notice] = "Editing <%= singular + ' ' if @include_object_names %>#{@<%= singular %>.<%= display_class %>} not authorized."
158
169
  render :index <% end %>
159
170
  end
160
171
 
@@ -3,7 +3,7 @@
3
3
  <\% if <%= singular %>.errors.any? %>
4
4
  <\%= render(partial: "<%= namespace_with_trailing_dash %>errors", locals: {resource: <%= singular %> }) %>
5
5
  <\% end %>
6
- <h2>Editing <\%= <%= singular %>.<%= display_class %> %></h2>
6
+ <h2>Editing <%= singular + " " if @include_object_names %><\%= <%= singular %>.<%= display_class %> %></h2>
7
7
  <\%= form_with model: <%= singular %>, url: <%= form_path_edit_helper %><%= ", html: {'data-turbo': false}" if @big_edit %> do |f| %>
8
8
  <\%= render partial: "<%= namespace_with_trailing_dash + @controller_build_folder + "/" %>form", locals: {:<%= singular %> => <%= singular %>, f: f}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> \%>
9
9
  <% if @edit_within_form_partial %><\%= render partial: "edit_within_form", locals: {f: f, <%= singular %>: <%= singular %>}<%= @nested_set.collect{|arg| ".merge(#{arg[:singular]} ? {#{arg[:singular]}: #{arg[:singular]}} : {})" }.join %> %><% end %>
@@ -7,7 +7,9 @@
7
7
  </h4><% end %>
8
8
  <% end %>
9
9
 
10
+ <% if @new_button_position == 'above' %>
10
11
  <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %><br /><% end %>
12
+ <% end %>
11
13
 
12
14
  <% unless @no_list %>
13
15
  <% unless @no_list_heading %>
@@ -66,5 +68,10 @@
66
68
  <% end %>
67
69
  <%= @no_paginate ? "" : paginate %>
68
70
  <% end %>
71
+
72
+
73
+ <% if @new_button_position == 'below' %>
74
+ <% unless @no_create %><%= '<%= render partial: "' + ((@namespace+"/" if @namespace) || "") + @controller_build_folder + '/new_button", locals: {}' + @nested_set.collect{|arg| ".merge(defined?(#{arg[:singular]}) ? {#{arg[:singular]}: #{arg[:singular]}} : {})"}.join() + ' %\>'.gsub('\\',"") %><br /><% end %>
75
+ <% end %>
69
76
  </div>
70
77
  <\% end %>
@@ -12,7 +12,12 @@
12
12
  <% downnest_object_name = eval("#{downnest_class}.table_name") %>
13
13
  <% downnest_style = @layout_strategy.downnest_style %>
14
14
  <% if !@stacked_downnesting %><div class="<%= @layout_strategy.downnest_portal_column_width(downnest) %> scaffold-downnest" <%= downnest_style %> ><% end %>
15
- <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {
15
+ <% if @downnest_shows_headings %>
16
+ <h3>
17
+ <%= downnest_object_name.pluralize.humanize %>
18
+ </h3>
19
+ <% end %>
20
+ <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {
16
21
  <%= @singular %>: <%= @singular %>,
17
22
  <%= downnest_object_name %>: <%= @singular %>.<%= downnest %>
18
23
  }
@@ -11,6 +11,7 @@
11
11
 
12
12
 
13
13
  <% if @downnest_children.any? && @big_edit %>
14
+ <hr />
14
15
  <% each_downnest_width = @downnest_children.count == 1 ? 33 : (53/@downnest_children.count).floor %>
15
16
  <% @downnest_object.each do |downnest, size| %>
16
17
  <div class="row">
@@ -20,7 +21,11 @@
20
21
  <% downnest_class = downnest_object.class_name %>
21
22
  <% downnest_object_name = eval("#{downnest_class}.table_name") %>
22
23
  <% downnest_style = @layout_strategy.downnest_style %>
23
-
24
+ <% if @downnest_shows_headings %>
25
+ <h3>
26
+ <%= downnest_class.titlecase.pluralize %>
27
+ </h3>
28
+ <% end %>
24
29
  <\%= render partial: "<%= namespace_with_trailing_dash %><%= downnest_object_name %>/list", locals: {<%= @singular %>: @<%= @singular %>, <%= downnest_object_name %>: @<%= @singular %>.<%= downnest %><% if @nested_set.any? %>, <%= @nested_set.collect{|x| "#{x[:singular]}: @#{x[:singular]}"}.join(", ") %>, nested_for: "<%= @nested_set.collect{|x| "#{x[:singular]}-" + "\#{" + "@#{x[:singular]}.id}"}.join("__") %>__<%= singular %>-#{@<%= @singular %>.id}" <% end %> } \%>
25
30
 
26
31
  </div>
@@ -4,12 +4,38 @@ class <%= ((@namespace.titleize.gsub(" ", "") + "::" if @namespace) || "") + @pl
4
4
  <% end %># <%= regenerate_me_code %><% if defined?(RuboCop) %>
5
5
  # rubocop:enable Layout/LineLength <% end %>
6
6
 
7
+
8
+ <% @nested_set.each do |nest| %>before_action :<%= nest[:singular] %>
9
+ def <%= nest[:singular] %>
10
+ @<%= nest[:singular] %> ||= current_user.accounts.find(params[:account_id])
11
+ end
12
+ <% end %>
13
+
14
+ <% nest_chain = [] %>
15
+ <% @nested_set.each { |arg|
16
+ if @auth_identifier == arg[:singular]
17
+ this_scope = auth_object
18
+ elsif nest_chain.empty?
19
+ this_scope = "#{@auth ? @auth : class_name}.#{arg[:plural]}"
20
+ else
21
+ this_scope = "#{nest_chain.last}.#{arg[:plural]}"
22
+ end
23
+ nest_chain << arg
24
+ }%>
25
+
7
26
  def index
8
27
  <% if @pundit %>authorize <%= @class_name %>, :typeahead? <% end %>
9
28
  query = params[:query]
10
29
  @typeahead_identifier = params[:typeahead_identifier]
11
- @<%= @plural %> = <%= @singular.titleize.gsub(" ", "") %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
12
30
 
31
+
32
+ <% if @nested_set.none? %>
33
+ @<%= @plural %> = <%= @singular.titleize.gsub(" ", "") %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
34
+ <% else %>
35
+ <% @nested_set.each do |arg| %>
36
+ @<%= @plural %> = <%= @nested_set.last[:singular] %>.<%= @plural %>.where("<%= @search_by.collect{|search| "LOWER(#{search}) LIKE ?" }.join(" OR ") %>", <%= @search_by.collect{|search| "\"%\#{query.downcase}%\"" }.join(", ") %>).limit(10)
37
+ <% end %>
38
+ <% end %>
13
39
  render layout: false
14
40
  end
15
41
  end
@@ -5,6 +5,10 @@ module HotGlue
5
5
  source_root File.expand_path('templates', __dir__)
6
6
  class_option :namespace, type: :string, default: nil
7
7
  class_option :search_by, type: :string, default: nil
8
+ class_option :nested, type: :string, default: nil
9
+ class_option :auth, type: :string, default: nil
10
+ class_option :auth_identifier, type: :string, default: nil
11
+
8
12
 
9
13
  include DefaultConfigLoader
10
14
  def filepath_prefix
@@ -28,6 +32,25 @@ module HotGlue
28
32
  @class_name = args.first
29
33
  @plural = args.first.tableize.pluralize
30
34
  @namespace = options['namespace']
35
+ @nested = options['nested'] if options['nested']
36
+
37
+ if !@nested.nil?
38
+ @nested_set = @nested.split("/").collect { |arg|
39
+ is_optional = arg.start_with?("~")
40
+ arg.gsub!("~", "")
41
+ {
42
+ singular: arg,
43
+ plural: arg.pluralize,
44
+ optional: is_optional
45
+ }
46
+ }
47
+ puts "NESTING: #{@nested_set}"
48
+ else
49
+ @nested_set = []
50
+ end
51
+
52
+ @auth = options['auth'] || "current_user"
53
+ @auth_identifier = options['auth_identifier'] || "user"
31
54
 
32
55
  if options['search_by']
33
56
  @search_by = options['search_by'].split(",")
@@ -1,5 +1,5 @@
1
1
  module HotGlue
2
2
  class Version
3
- CURRENT = '0.6.10'
3
+ CURRENT = '0.6.12'
4
4
  end
5
5
  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.6.10
4
+ version: 0.6.12
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: 2024-12-25 00:00:00.000000000 Z
11
+ date: 2025-02-20 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails