hot-glue 0.7.8 → 0.8
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 +2 -2
- data/README.md +30 -6
- data/app/helpers/hot_glue_helper.rb +32 -0
- data/lib/generators/hot_glue/fields/association_field.rb +4 -0
- data/lib/generators/hot_glue/fields/field.rb +6 -2
- data/lib/generators/hot_glue/fields/float_field.rb +1 -1
- data/lib/generators/hot_glue/install_generator.rb +56 -2
- data/lib/generators/hot_glue/markup_templates/erb.rb +10 -3
- data/lib/generators/hot_glue/scaffold_generator.rb +48 -3
- data/lib/generators/hot_glue/templates/capybara_login.rb +0 -5
- data/lib/generators/hot_glue/templates/controller.rb.erb +2 -0
- data/lib/hotglue/version.rb +1 -1
- data/script/clean_generated_code +1 -0
- 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: 555bc8c92663c9e6797856debce6569ef5532f1d8f0536d862f1226b08b3e297
|
|
4
|
+
data.tar.gz: 2cc566882dc10083d857ebf8e254a126cf2842cde280509ff56ce37a86c4766e
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 9592d760df6d8b79e41fdd71bb8e8a89f62745056c512b56cf1d31bed0174e9169146531febdec68dfb7ca2017e26e048f52055718ab04279e444c2742016482
|
|
7
|
+
data.tar.gz: c4e5ab6b7289ba6ac225eb4f40267bd2bb5b0163b1dc029ba43b55161552255ae4e541028a89aa4b988f6a83ea8123da7102216d4afe52a226dead4ca0e71c98
|
data/Gemfile.lock
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
PATH
|
|
2
2
|
remote: .
|
|
3
3
|
specs:
|
|
4
|
-
hot-glue (0.7.
|
|
4
|
+
hot-glue (0.7.9)
|
|
5
5
|
ffaker (~> 2.16)
|
|
6
6
|
rails (> 5.1)
|
|
7
7
|
|
|
@@ -134,7 +134,7 @@ GEM
|
|
|
134
134
|
net-protocol
|
|
135
135
|
net-pop (0.1.2)
|
|
136
136
|
net-protocol
|
|
137
|
-
net-protocol (0.
|
|
137
|
+
net-protocol (0.3.0)
|
|
138
138
|
timeout
|
|
139
139
|
net-smtp (0.5.1)
|
|
140
140
|
net-protocol
|
data/README.md
CHANGED
|
@@ -1096,8 +1096,6 @@ The effect will be that the fields will be stacked together into nicely fit colu
|
|
|
1096
1096
|
|
|
1097
1097
|
**If your customer is used to Excel, this feature will confuse them.**
|
|
1098
1098
|
|
|
1099
|
-
Also, this feature will **probably not** be supported by the SORTING (not yet implemented). (You will be forced to choose between the two which I think makes sense.)
|
|
1100
|
-
|
|
1101
1099
|
The layout builder works from right-to-left and starts with 12, the number of Bootstrap's columns.
|
|
1102
1100
|
|
|
1103
1101
|
It reserves 2 columns for the default buttons. Then +1 additional column for **each magic button** you have specified.
|
|
@@ -2000,6 +1998,17 @@ _Notice that Stimulus requires object registration when used in a Node environme
|
|
|
2000
1998
|
Instead, use the generator and the registry will be updated for you automatically.
|
|
2001
1999
|
|
|
2002
2000
|
|
|
2001
|
+
## Sorting
|
|
2002
|
+
|
|
2003
|
+
#### `--sortable` (true of flagged; false otherwise; does not take an argument)
|
|
2004
|
+
To add sorting to your columns add `--sortable` to your build
|
|
2005
|
+
sortable fields are integers, floats, string, text, datetime, time, dates excluding anything that is a foreign key, not UUIDs
|
|
2006
|
+
|
|
2007
|
+
#### `--sort-fields=`
|
|
2008
|
+
List of field names (separated by commas)
|
|
2009
|
+
Leave off (do not specify) to sort by all sort-eligible fields
|
|
2010
|
+
|
|
2011
|
+
|
|
2003
2012
|
## Attachments
|
|
2004
2013
|
|
|
2005
2014
|
#### `--attachments=` Long form syntax with 1st and 2nd parameters
|
|
@@ -2489,6 +2498,20 @@ These automatic pickups for partials are detected at build time. This means that
|
|
|
2489
2498
|
|
|
2490
2499
|
# VERSION HISTORY
|
|
2491
2500
|
|
|
2501
|
+
#### 2026-08-30 - v0.8
|
|
2502
|
+
- `--sortable` (true of flagged; false otherwise; does not take an argument)
|
|
2503
|
+
To add sorting to your columns add `--sortable` to your build
|
|
2504
|
+
sortable fields are integers, floats, string, text, datetime, time, dates excluding anything that is a foreign key, not UUIDs
|
|
2505
|
+
- `--sort-fields=`
|
|
2506
|
+
List of field names (separated by commas)
|
|
2507
|
+
Leave off (do not specify) to sort by all sort-eligible fields
|
|
2508
|
+
|
|
2509
|
+
|
|
2510
|
+
#### 2026-08-29 - v0.7.9
|
|
2511
|
+
- Render float fields as type="number" step="any" for HTML5 validation; float fields should not be correctly validated on input
|
|
2512
|
+
|
|
2513
|
+
- switching 'feature' specs to be 'system' specs, switch to spec/system with shared DB connection, headless=new Chrome, and whole-example retry via rspec-retry; should address race conditions in specs
|
|
2514
|
+
|
|
2492
2515
|
#### 2026-08-22 - v0.7.8
|
|
2493
2516
|
- fix for time field output when no user is present (in gd mode)
|
|
2494
2517
|
- in new builds, create and edit will now interact as turbo-stream interactions (except for big edit); this is to remove a race condition in the capy spec; note that your old edit.erb and new.erb will get deleted if you rebuild
|
|
@@ -2518,12 +2541,13 @@ for example, if we have a `thing` that can belong (via parent_id and parent_type
|
|
|
2518
2541
|
|
|
2519
2542
|
Hot glue wil convert the spaces to commas when writing the controller code.
|
|
2520
2543
|
|
|
2521
|
-
A child controller
|
|
2522
|
-
|
|
2544
|
+
A child controller with a polymorphic parent:
|
|
2545
|
+
|
|
2546
|
+
- This special case assumes that that the parent being build is not actually a polymoprh, it is a real object, but its children have foreign keys to it which are polymorphic.
|
|
2523
2547
|
|
|
2524
|
-
`--nested=abc(parent)
|
|
2548
|
+
`--nested=abc(parent)`
|
|
2525
2549
|
|
|
2526
|
-
Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so
|
|
2550
|
+
Example: In my data model, targets have a polymorphic parent (parent_id and parent_type) and can belong to either Companies or Schools. Here, we are building the Companies view with a child to Targets, but notice for these targets we are using polymorphism and also using a controller prefix, so that this child controller will be built as CompanyTargets. In the companies build, we downnest `company_targets(targets)` (`company_targets` is the name of the child controller, but it is acting on an object called `targets`, as seen in the downnest specification.)
|
|
2527
2551
|
|
|
2528
2552
|
```
|
|
2529
2553
|
bin/rails generate hot_glue:scaffold Company --namespace='account_dashboard' --nested='account' --downnest='company_targets(targets)'
|
|
@@ -10,4 +10,36 @@ module HotGlueHelper
|
|
|
10
10
|
def enum_to_collection_select(hash)
|
|
11
11
|
hash.collect{|k,v| KVObject.new(key: k, value: v)}
|
|
12
12
|
end
|
|
13
|
+
|
|
14
|
+
def sort_link(field, label)
|
|
15
|
+
field = field.to_s
|
|
16
|
+
active = params[:sort] == field
|
|
17
|
+
direction = active ? params[:direction] : nil
|
|
18
|
+
|
|
19
|
+
next_direction =
|
|
20
|
+
if !active
|
|
21
|
+
'asc'
|
|
22
|
+
elsif direction == 'asc'
|
|
23
|
+
'desc'
|
|
24
|
+
else
|
|
25
|
+
nil
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
new_params = request.query_parameters.except('sort', 'direction', 'page')
|
|
29
|
+
if next_direction
|
|
30
|
+
new_params['sort'] = field
|
|
31
|
+
new_params['direction'] = next_direction
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
arrow =
|
|
35
|
+
if active && direction == 'asc'
|
|
36
|
+
' ▲'
|
|
37
|
+
elsif active && direction == 'desc'
|
|
38
|
+
' ▼'
|
|
39
|
+
else
|
|
40
|
+
''
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
link_to (label + arrow).html_safe, "#{request.path}?#{new_params.to_query}".chomp('?'), style: 'white-space: nowrap', 'data-turbo-action': 'advance'
|
|
44
|
+
end
|
|
13
45
|
end
|
|
@@ -52,6 +52,10 @@ class Field
|
|
|
52
52
|
@name
|
|
53
53
|
end
|
|
54
54
|
|
|
55
|
+
def sortable?
|
|
56
|
+
true
|
|
57
|
+
end
|
|
58
|
+
|
|
55
59
|
def form_field_output
|
|
56
60
|
raise "superclass must implement"
|
|
57
61
|
end
|
|
@@ -171,13 +175,13 @@ class Field
|
|
|
171
175
|
res
|
|
172
176
|
end
|
|
173
177
|
|
|
174
|
-
def field_output(type = nil, width )
|
|
178
|
+
def field_output(type = nil, width, step: nil)
|
|
175
179
|
if modify_as && modify_as[:timezone]
|
|
176
180
|
"<%= f.time_zone_select :#{name}, ActiveSupport::TimeZone.all, {}, {class: 'form-control'} %>"
|
|
177
181
|
else
|
|
178
182
|
parts = name.split('_')
|
|
179
183
|
camelcase_name = parts.first + parts[1..].map(&:capitalize).join
|
|
180
|
-
" <%= f.text_field :#{name}, value: #{singular}.#{name}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}'" + (form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + " %>\n " + "\n"
|
|
184
|
+
" <%= f.text_field :#{name}, value: #{singular}.#{name}, autocomplete: 'off', size: #{width}, class: 'form-control', type: '#{type}'" + (step ? ", step: '#{step}'" : "") + (form_placeholder_labels ? ", placeholder: '#{name.to_s.humanize}'" : "") + (stimmify ? ", 'data-#{@stimmify}-target': '#{camelcase_name}' " : "") + " %>\n " + "\n"
|
|
181
185
|
end
|
|
182
186
|
end
|
|
183
187
|
|
|
@@ -56,6 +56,17 @@ module HotGlue
|
|
|
56
56
|
|
|
57
57
|
|
|
58
58
|
|
|
59
|
+
begin
|
|
60
|
+
gemfile_contents = File.read("Gemfile")
|
|
61
|
+
if !gemfile_contents.include?("rspec-retry")
|
|
62
|
+
gemfile_contents.gsub!(/^group :test do/, "group :test do\n gem \"rspec-retry\"")
|
|
63
|
+
File.write("Gemfile", gemfile_contents)
|
|
64
|
+
puts " HOTGLUE --> added to Gemfile: `gem \"rspec-retry\"` -- run `bundle install` "
|
|
65
|
+
end
|
|
66
|
+
rescue StandardError => e
|
|
67
|
+
puts "WARNING: error writing to Gemfile --- #{e.message}"
|
|
68
|
+
end
|
|
69
|
+
|
|
59
70
|
begin
|
|
60
71
|
rails_helper_contents = File.read("#{filepath_prefix}spec/rails_helper.rb")
|
|
61
72
|
if !rails_helper_contents.include?("Capybara.default_driver =")
|
|
@@ -63,6 +74,11 @@ module HotGlue
|
|
|
63
74
|
puts " HOTGLUE --> added to spec/rails_helper.rb: `Capybara.default_driver = :selenium_chrome_headless` "
|
|
64
75
|
end
|
|
65
76
|
|
|
77
|
+
if !rails_helper_contents.include?("Capybara.default_max_wait_time")
|
|
78
|
+
rails_helper_contents << "\n\n# Default of 2s is too tight for headless Chrome + Devise + Turbo page\n# renders under load, causing sporadic false-negative waits.\nCapybara.default_max_wait_time = 5\n"
|
|
79
|
+
puts " HOTGLUE --> added to spec/rails_helper.rb: `Capybara.default_max_wait_time = 5` "
|
|
80
|
+
end
|
|
81
|
+
|
|
66
82
|
if !rails_helper_contents.include?("include FactoryBot::Syntax::Methods")
|
|
67
83
|
rails_helper_contents.gsub!("RSpec.configure do |config|", "RSpec.configure do |config| \n
|
|
68
84
|
config.include FactoryBot::Syntax::Methods
|
|
@@ -70,9 +86,46 @@ module HotGlue
|
|
|
70
86
|
puts " HOTGLUE --> added to #{filepath_prefix}spec/rails_helper.rb: `config.include FactoryBot::Syntax::Methods` "
|
|
71
87
|
end
|
|
72
88
|
|
|
89
|
+
if !rails_helper_contents.include?("type: :system) do")
|
|
90
|
+
rails_helper_contents.gsub!("RSpec.configure do |config|", "RSpec.configure do |config| \n
|
|
91
|
+
# spec/system specs run through ActionDispatch::SystemTestCase, which shares
|
|
92
|
+
# the DB connection between the test thread and the in-process Puma server
|
|
93
|
+
# thread. Plain :feature specs with a real Selenium driver don't get this,
|
|
94
|
+
# which causes intermittent \"record not visible to the server thread\"
|
|
95
|
+
# failures (e.g. login appearing to fail right after the user was created).
|
|
96
|
+
#
|
|
97
|
+
# We use :chrome (not Rails' :headless_chrome) because
|
|
98
|
+
# ActionDispatch::SystemTesting::Browser hardcodes the legacy `--headless`
|
|
99
|
+
# flag. Legacy headless Chrome runs a materially different rendering/input
|
|
100
|
+
# pipeline than real Chrome and has known bugs where a native click never
|
|
101
|
+
# reaches the page. `--headless=new` (Chrome 109+) doesn't have this problem.
|
|
102
|
+
config.before(:each, type: :system) do
|
|
103
|
+
driven_by :selenium, using: :chrome, screen_size: [1366, 1200] do |options|
|
|
104
|
+
options.add_argument(\"--headless=new\")
|
|
105
|
+
end
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Real-browser system specs still hit transient, infrastructure-level
|
|
109
|
+
# flakiness that has nothing to do with application correctness (a click
|
|
110
|
+
# occasionally dropped by the browser, a Turbo navigation racing a
|
|
111
|
+
# Capybara content read into an error Capybara doesn't retry on its own).
|
|
112
|
+
# Retrying the whole example -- rather than chasing each transient error
|
|
113
|
+
# class individually -- is the standard fix for this. rspec-retry
|
|
114
|
+
# re-instantiates the example group on retry so `let`/`let!` factories
|
|
115
|
+
# actually re-run instead of reusing stale memoized state.
|
|
116
|
+
config.verbose_retry = true
|
|
117
|
+
config.default_retry_count = 3
|
|
118
|
+
config.retry_callback = proc { Capybara.reset_sessions! }
|
|
119
|
+
config.around(:each, type: :system) do |example|
|
|
120
|
+
example.run_with_retry retry: 3
|
|
121
|
+
end
|
|
122
|
+
")
|
|
123
|
+
puts " HOTGLUE --> added to #{filepath_prefix}spec/rails_helper.rb: `config.before(:each, type: :system) { driven_by :selenium, using: :chrome, --headless=new }` and rspec-retry config "
|
|
124
|
+
end
|
|
125
|
+
|
|
73
126
|
if ! rails_helper_contents.include?("require 'support/capybara_login.rb'")
|
|
74
|
-
rails_helper_contents.gsub!("require 'rspec/rails'","require 'rspec/rails' \nrequire 'support/capybara_login.rb'")
|
|
75
|
-
puts " HOTGLUE --> added to spec/rails_helper.rb: `require 'support/capybara_login.rb'` "
|
|
127
|
+
rails_helper_contents.gsub!("require 'rspec/rails'","require 'rspec/rails' \nrequire 'rspec/retry' \nrequire 'support/capybara_login.rb'")
|
|
128
|
+
puts " HOTGLUE --> added to spec/rails_helper.rb: `require 'rspec/retry'` and `require 'support/capybara_login.rb'` "
|
|
76
129
|
end
|
|
77
130
|
File.write("#{filepath_prefix}spec/rails_helper.rb", rails_helper_contents)
|
|
78
131
|
|
|
@@ -138,6 +191,7 @@ module HotGlue
|
|
|
138
191
|
rescue StandardError => e
|
|
139
192
|
puts "WARNING: error writing to #{Rails.env.test? ? 'spec/dummmy/' : ''}spec/support/capybara_login.rb --- #{e.message}"
|
|
140
193
|
end
|
|
194
|
+
|
|
141
195
|
end
|
|
142
196
|
end
|
|
143
197
|
end
|
|
@@ -13,7 +13,7 @@ module HotGlue
|
|
|
13
13
|
:form_path, :layout_object, :search_clear_button, :search_autosearch,
|
|
14
14
|
:stimmify, :stimmify_camel, :hidden_create, :hidden_update, :invisible_create,
|
|
15
15
|
:invisible_update, :plural, :phantom_search, :pagination_style,
|
|
16
|
-
:namespace, :controller_build_folder
|
|
16
|
+
:namespace, :controller_build_folder, :sortable, :sortable_fields
|
|
17
17
|
|
|
18
18
|
|
|
19
19
|
def initialize(singular:, singular_class: ,
|
|
@@ -27,9 +27,12 @@ module HotGlue
|
|
|
27
27
|
search_clear_button:, search_autosearch:, layout_object:,
|
|
28
28
|
form_path: , stimmify: , stimmify_camel:, hidden_create:, hidden_update: ,
|
|
29
29
|
invisible_create:, invisible_update: , plural: , phantom_search:,
|
|
30
|
-
pagination_style:, namespace: nil, controller_build_folder: nil
|
|
30
|
+
pagination_style:, namespace: nil, controller_build_folder: nil,
|
|
31
|
+
sortable: false, sortable_fields: [] )
|
|
31
32
|
|
|
32
33
|
|
|
34
|
+
@sortable = sortable
|
|
35
|
+
@sortable_fields = sortable_fields
|
|
33
36
|
@form_path = form_path
|
|
34
37
|
@search = search
|
|
35
38
|
@search_fields = search_fields
|
|
@@ -106,7 +109,11 @@ module HotGlue
|
|
|
106
109
|
"<div class='#{layout_strategy.column_classes_for_column_headings(size)} hg-heading-row heading--#{singular}--#{column.join("-")}' " + col_style + ">" +
|
|
107
110
|
column.map(&:to_s).map{|col_name|
|
|
108
111
|
unless col_name.starts_with?("**")
|
|
109
|
-
|
|
112
|
+
if @sortable && @sortable_fields.collect(&:to_s).include?(col_name)
|
|
113
|
+
the_output = "<%= sort_link(:#{col_name}, '#{col_name.humanize}') %>"
|
|
114
|
+
else
|
|
115
|
+
the_output = "#{col_name.humanize}"
|
|
116
|
+
end
|
|
110
117
|
else
|
|
111
118
|
the_output = ""
|
|
112
119
|
end
|
|
@@ -34,7 +34,8 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
34
34
|
:search_clear_button, :search_autosearch, :include_object_names,
|
|
35
35
|
:stimmify, :stimmify_camel, :hidden_create, :hidden_update,
|
|
36
36
|
:invisible_create, :invisible_update, :phantom_create_params,
|
|
37
|
-
:phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents
|
|
37
|
+
:phantom_update_params, :lazy, :back_link_to_parent, :polymorphic_parents,
|
|
38
|
+
:sortable, :sortable_fields
|
|
38
39
|
|
|
39
40
|
# important: using an attr_accessor called :namespace indirectly causes a conflict with Rails class_name method
|
|
40
41
|
# so we use namespace_value instead
|
|
@@ -144,6 +145,10 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
144
145
|
|
|
145
146
|
class_option :phantom_search, default: nil
|
|
146
147
|
|
|
148
|
+
# SORT OPTIONS
|
|
149
|
+
class_option :sortable, type: :boolean, default: false
|
|
150
|
+
class_option :sort_fields, default: nil # comma separated whitelist; defaults to all sortable-type fields
|
|
151
|
+
|
|
147
152
|
|
|
148
153
|
|
|
149
154
|
def initialize(*meta_args)
|
|
@@ -752,6 +757,27 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
752
757
|
@columns_map[col] = this_column_object.field
|
|
753
758
|
end
|
|
754
759
|
|
|
760
|
+
@sortable = options['sortable']
|
|
761
|
+
|
|
762
|
+
if @sortable
|
|
763
|
+
if options['sort_fields']
|
|
764
|
+
@sortable_fields = options['sort_fields'].split(',').collect(&:to_sym)
|
|
765
|
+
@sortable_fields.each do |field|
|
|
766
|
+
if !@columns_map[field]
|
|
767
|
+
raise "You specified a sort field for #{field} but that field is not in the list of columns"
|
|
768
|
+
elsif !@columns_map[field].sortable?
|
|
769
|
+
raise "You specified a sort field for #{field} but that field type cannot be sorted (e.g. an association or a UUID)"
|
|
770
|
+
end
|
|
771
|
+
end
|
|
772
|
+
else
|
|
773
|
+
@sortable_fields = @columns_map.select { |col, field| field.sortable? }.keys
|
|
774
|
+
end
|
|
775
|
+
|
|
776
|
+
warn_about_unindexed_sortable_fields
|
|
777
|
+
else
|
|
778
|
+
@sortable_fields = []
|
|
779
|
+
end
|
|
780
|
+
|
|
755
781
|
|
|
756
782
|
@columns_map.each do |key, field|
|
|
757
783
|
if field.is_a?(AssociationField)
|
|
@@ -928,7 +954,9 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
928
954
|
phantom_search: @phantom_search,
|
|
929
955
|
pagination_style: @pagination_style,
|
|
930
956
|
namespace: @namespace,
|
|
931
|
-
controller_build_folder: @controller_build_folder
|
|
957
|
+
controller_build_folder: @controller_build_folder,
|
|
958
|
+
sortable: @sortable,
|
|
959
|
+
sortable_fields: @sortable_fields
|
|
932
960
|
)
|
|
933
961
|
elsif @markup == "slim"
|
|
934
962
|
raise(HotGlue::Error, "SLIM IS NOT IMPLEMENTED")
|
|
@@ -1265,7 +1293,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1265
1293
|
end
|
|
1266
1294
|
|
|
1267
1295
|
unless @no_specs
|
|
1268
|
-
dest_file = File.join("#{filepath_prefix}spec/
|
|
1296
|
+
dest_file = File.join("#{filepath_prefix}spec/system#{namespace_with_dash}", "#{plural}_behavior_spec.rb")
|
|
1269
1297
|
|
|
1270
1298
|
if File.exist?(dest_file)
|
|
1271
1299
|
existing_file = File.open(dest_file)
|
|
@@ -1997,6 +2025,17 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1997
2025
|
end
|
|
1998
2026
|
|
|
1999
2027
|
|
|
2028
|
+
def warn_about_unindexed_sortable_fields
|
|
2029
|
+
indexed_columns = @the_object.connection.indexes(@the_object.table_name).collect { |index| index.columns.first }
|
|
2030
|
+
unindexed = @sortable_fields.reject { |field| indexed_columns.include?(field.to_s) }
|
|
2031
|
+
return if unindexed.empty?
|
|
2032
|
+
|
|
2033
|
+
puts "********************"
|
|
2034
|
+
puts "WARNING: The following fields are sortable but have no database index, which may cause slow queries as the table grows: #{unindexed.join(', ')}"
|
|
2035
|
+
puts "Consider adding indexes, e.g.: " + unindexed.collect { |field| "add_index :#{plural}, :#{field}" }.join("; ")
|
|
2036
|
+
puts "********************"
|
|
2037
|
+
end
|
|
2038
|
+
|
|
2000
2039
|
def load_all_code
|
|
2001
2040
|
# the inner method definition of the load_all_* method
|
|
2002
2041
|
res = +""
|
|
@@ -2068,6 +2107,12 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
2068
2107
|
res << "\n"
|
|
2069
2108
|
end
|
|
2070
2109
|
|
|
2110
|
+
if @sortable
|
|
2111
|
+
res << "\n"
|
|
2112
|
+
res << " if SORTABLE_FIELDS.include?(params[:sort]) && %w[asc desc].include?(params[:direction])\n"
|
|
2113
|
+
res << " @#{plural} = @#{plural}.order(params[:sort] => params[:direction].to_sym)\n"
|
|
2114
|
+
res << " end"
|
|
2115
|
+
end
|
|
2071
2116
|
|
|
2072
2117
|
if @pagination_style == "kaminari"
|
|
2073
2118
|
res << " @#{plural} = @#{plural}.page(params[:page])#{ ".per(per)" if @paginate_per_page_selector }"
|
|
@@ -6,10 +6,5 @@ def login_as(user)
|
|
|
6
6
|
end
|
|
7
7
|
click_button 'Log in'
|
|
8
8
|
|
|
9
|
-
# headless Chrome/Selenium occasionally drops this click without submitting
|
|
10
|
-
# the form at all (confirmed via server log: no POST /users/sign_in received).
|
|
11
|
-
# Retry once before failing for real.
|
|
12
|
-
click_button 'Log in' unless page.has_content?('Signed in successfully', wait: 3)
|
|
13
|
-
|
|
14
9
|
expect(page).to have_content("Signed in successfully")
|
|
15
10
|
end
|
|
@@ -77,6 +77,8 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
77
77
|
params[:per] || 10
|
|
78
78
|
end<% end %>
|
|
79
79
|
<% unless @no_list %>
|
|
80
|
+
<% if @sortable %> SORTABLE_FIELDS = %w[<%= @sortable_fields.join(' ') %>].freeze
|
|
81
|
+
<% end %>
|
|
80
82
|
def load_all_<%= plural %><% if @search == "set" %>
|
|
81
83
|
@q = params[:q] || <%= search_default %> <% end %>
|
|
82
84
|
<%= load_all_code %>
|
data/lib/hotglue/version.rb
CHANGED
data/script/clean_generated_code
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.
|
|
4
|
+
version: '0.8'
|
|
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: 2026-08-
|
|
11
|
+
date: 2026-08-30 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|