hot-glue 0.6.10 → 0.6.11

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: a9b9cdb44bde02376148703d050944c0c7cc169b42349b021539098afd8532bf
4
+ data.tar.gz: e4baffd1a1d3d4cf01b811c850b02827c803f7d1188a5b5166f40b11730a0821
5
5
  SHA512:
6
- metadata.gz: 47afa457097e68f69f7aaa85d07f8ebe70d47f052875eb52863796122846e9b8993d13e678e8eb927ce44a0331b2a56972a189d8af0e1c4272bd2b2661837548
7
- data.tar.gz: 525847e13f04fec313576a235d864fa2a59781d448bd4a94ed2425d0c2bbb508efd83f0b97d37a9f9f5ab5af7f49b5d9e6dc3797648e5ab39bf7b67823794ef8
6
+ metadata.gz: f298a2685d19ebc5a27c16d72cb05806a74bdf3ffbe15b7f85e799164e0d4c56ae1605d950a0843749a3db840c957d1f8a30feb27d68b276656a277a3dd21d53
7
+ data.tar.gz: e5984cc18282e0b5b99f5992d764395dc9964c1a81b08c6848d9f498564e04e8623275fd40b4c67ca2759d400fe3d4e952ea4db61aada50a63f7fab3ef67a6d9
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
 
@@ -1663,6 +1749,42 @@ These automatic pickups for partials are detected at buildtime. This means that
1663
1749
 
1664
1750
  # VERSION HISTORY
1665
1751
 
1752
+
1753
+ #### 2025-01-28 v0.6.11
1754
+
1755
+ • Typeahead now can use --auth, --auth-identifier, --namespace, and --nested
1756
+ • Works similar to how same flags work on scaffold generator. (Notice that the typeahead generator is a completely separate generator).
1757
+ • When using nested, your results are scoped the parent objects in the nest chain (which is the last one)
1758
+
1759
+ e.g.
1760
+ `bin/rails generate hot_glue:scaffold Member --auth='current_user' --auth-identifier='user' --auth-identifier=user --modify='user_id{typeahead}[account]'`
1761
+
1762
+ here the user_id field on members will use a typeahead that is built in the namespace `account_dashboard` under 1 parent: `account`
1763
+
1764
+ This would be used in conjunction with a typeahead built using the same namespace and nesting that matches:
1765
+
1766
+ ```
1767
+ bin/rails generate hot_glue:typeahead User --namespace='account_dashboard' --nested='account' --auth-identifier='user' --auth='current_user'
1768
+ ```
1769
+
1770
+ (See 'typeahead' section for details)
1771
+
1772
+ `--include-object-names`
1773
+
1774
+ When you are "Editing X" we specify that X is a ___ (author, book, room, etc)
1775
+
1776
+ e.g. "Editing author Edgar Allan Poe" vs "Editing Edgar Allan Poe"
1777
+
1778
+ Can also be specified globally in `config/hot_glue.yml`
1779
+
1780
+
1781
+ `--new-button-position` (above, below; default: above)
1782
+ Show the new button above or below the list.
1783
+
1784
+ `--downnest-shows-headings` (default: false)
1785
+ Show headings above downnested portals.
1786
+
1787
+
1666
1788
  #### 2024-12-25 v0.6.10
1667
1789
  • adds `--no-nav-menu` option to supress writing to the _nav template
1668
1790
  • the _nav template itself can now end with either .html.erb or .erb
@@ -110,7 +110,15 @@ class AssociationField < Field
110
110
  # else
111
111
  # end
112
112
  elsif modify_as && modify_as[:typeahead]
113
- search_url = "#{namespace ? namespace + "_" : ""}#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
113
+ search_url = "#{namespace ? namespace + "_" : ""}" +
114
+ modify_as[:nested].join("_") +
115
+ + "_#{assoc.class_name.downcase.pluralize}_typeahead_index_url"
116
+
117
+
118
+ if @modify_as[:nested].any?
119
+ search_url << "(" + modify_as[:nested].collect{|x| "#{x}"}.join(",") + ")"
120
+ end
121
+
114
122
  "<div class='typeahead typeahead--#{assoc.name}_id'
115
123
  data-controller='typeahead'
116
124
  data-typeahead-url-value='<%= #{search_url} %>'
@@ -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
 
@@ -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,8 @@ 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
+ nested = $3.split("/")
266
+ @modify_as[key.to_sym] = {typeahead: 1, nested: nested}
264
267
  elsif $2 == "timezone"
265
268
  @modify_as[key.to_sym] = {timezone: 1, badges: $3}
266
269
  elsif $2 == "none"
@@ -337,6 +340,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
337
340
 
338
341
  @smart_layout = options['smart_layout']
339
342
  @record_scope = options['record_scope']
343
+ @downnest_shows_headings = options['downnest_shows_headings']
344
+ @new_button_position = options['new_button_position']
345
+
340
346
 
341
347
  @pundit = options['pundit']
342
348
 
@@ -361,6 +367,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
361
367
  @downnest_object = HotGlue.construct_downnest_object(@downnest)
362
368
  end
363
369
 
370
+ @include_object_names = options['include_object_names'] || get_default_from_config(key: :include_object_names)
371
+
372
+
373
+
364
374
  if @god
365
375
  # @auth = nil
366
376
  end
@@ -463,6 +473,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
463
473
  identify_object_owner
464
474
  setup_fields
465
475
 
476
+
466
477
  if (@columns - @show_only - (@ownership_field ? [@ownership_field.to_sym] : [])).empty?
467
478
  @no_field_form = true
468
479
  end
@@ -1069,7 +1080,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1069
1080
  HotGlue.optionalized_ternary(namespace: @namespace,
1070
1081
  target: @controller_build_folder,
1071
1082
  nested_set: @nested_set,
1072
- with_params: true,
1083
+ with_params: false,
1073
1084
  top_level: false)
1074
1085
  end
1075
1086
 
@@ -1077,7 +1088,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1077
1088
  HotGlue.optionalized_ternary(namespace: @namespace,
1078
1089
  target: @singular,
1079
1090
  nested_set: @nested_set,
1080
- with_params: true,
1091
+ with_params: false,
1081
1092
  put_form: true,
1082
1093
  top_level: false)
1083
1094
  end
@@ -1086,7 +1097,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1086
1097
  HotGlue.optionalized_ternary(namespace: @namespace,
1087
1098
  target: @singular,
1088
1099
  nested_set: @nested_set,
1089
- with_params: true,
1100
+ with_params: false,
1090
1101
  put_form: true)
1091
1102
  end
1092
1103
 
@@ -1095,7 +1106,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1095
1106
  target: @singular,
1096
1107
  nested_set: @nested_set,
1097
1108
  modifier: "edit_",
1098
- with_params: true,
1109
+ with_params: false,
1099
1110
  put_form: true)
1100
1111
  end
1101
1112
 
@@ -1124,7 +1135,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1124
1135
  target: singular,
1125
1136
  nested_set: @nested_set,
1126
1137
  modifier: "new_",
1127
- with_params: true)
1138
+ with_params: false)
1128
1139
  end
1129
1140
 
1130
1141
  def nested_assignments
@@ -1222,7 +1233,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
1222
1233
  path: HotGlue.optionalized_ternary( namespace: @namespace,
1223
1234
  target: @singular,
1224
1235
  nested_set: @nested_set,
1225
- with_params: true,
1236
+ with_params: false,
1226
1237
  put_form: true),
1227
1238
  big_edit: @big_edit,
1228
1239
  singular: singular,
@@ -154,7 +154,7 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
154
154
  @action = 'edit'
155
155
  render :edit<% if @pundit %>
156
156
  rescue Pundit::NotAuthorizedError
157
- flash[:notice] = "Editing #{@<%= singular %>.<%= display_class %>} not authorized."
157
+ flash[:notice] = "Editing <%= singular + ' ' if @include_object_names %>#{@<%= singular %>.<%= display_class %>} not authorized."
158
158
  render :index <% end %>
159
159
  end
160
160
 
@@ -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
  }
@@ -20,7 +20,11 @@
20
20
  <% downnest_class = downnest_object.class_name %>
21
21
  <% downnest_object_name = eval("#{downnest_class}.table_name") %>
22
22
  <% downnest_style = @layout_strategy.downnest_style %>
23
-
23
+ <% if @downnest_shows_headings %>
24
+ <h3>
25
+ <%= downnest_class.humanize %>
26
+ </h3>
27
+ <% end %>
24
28
  <\%= 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
29
 
26
30
  </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.11'
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.11
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-01-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails