hot-glue 0.7.7 → 0.7.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/.ruby-version +1 -1
- data/Gemfile.lock +7 -6
- data/README.md +8 -0
- data/app/helpers/hot_glue/controller_helper.rb +3 -2
- data/lib/generators/hot_glue/fields/association_field.rb +1 -1
- data/lib/generators/hot_glue/fields/date_time_field.rb +7 -2
- data/lib/generators/hot_glue/fields/time_field.rb +2 -2
- data/lib/generators/hot_glue/scaffold_generator.rb +43 -6
- data/lib/generators/hot_glue/templates/capybara_login.rb +7 -0
- data/lib/generators/hot_glue/templates/controller.rb.erb +7 -2
- data/lib/generators/hot_glue/templates/erb/_new_button.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/_show.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/edit.turbo_stream.erb +1 -1
- data/lib/generators/hot_glue/templates/erb/new.turbo_stream.erb +3 -0
- data/lib/generators/hot_glue/templates/system_spec.rb.erb +1 -1
- data/lib/hotglue/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 0e4491ce711db972625af0df18b41705f69a87451b34237a1a3ab1c565fc4729
|
|
4
|
+
data.tar.gz: 13799e4f92016ccf6156abf90a85cd5bda7418b1287ce3d7c112112b853ff92f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 32a835125c53bd4aa3d14080ac048c17d556db3b6db7716ce4a21eefba18db38fe33f76403e16f5e8a2f9415d6591430412d0a33029d0634ec65118f8363d345
|
|
7
|
+
data.tar.gz: 55a21a7aba9909332640275d0b6cb24dcfb0784323eb9ca7e8248db70143ec4a6520f4c1537aa39c25ca36c4ac3f844ec42eab20e3345db3298915569c203897
|
data/.ruby-version
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
3.
|
|
1
|
+
3.3.10
|
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.7)
|
|
5
5
|
ffaker (~> 2.16)
|
|
6
6
|
rails (> 5.1)
|
|
7
7
|
|
|
@@ -117,19 +117,19 @@ GEM
|
|
|
117
117
|
loofah (2.19.0)
|
|
118
118
|
crass (~> 1.0.2)
|
|
119
119
|
nokogiri (>= 1.5.9)
|
|
120
|
-
mail (2.9.
|
|
120
|
+
mail (2.9.1)
|
|
121
121
|
logger
|
|
122
122
|
mini_mime (>= 0.1.1)
|
|
123
123
|
net-imap
|
|
124
124
|
net-pop
|
|
125
125
|
net-smtp
|
|
126
|
-
marcel (1.1
|
|
126
|
+
marcel (1.2.1)
|
|
127
127
|
matrix (0.4.2)
|
|
128
128
|
method_source (1.0.0)
|
|
129
129
|
mini_mime (1.1.2)
|
|
130
130
|
mini_portile2 (2.8.4)
|
|
131
131
|
minitest (5.16.3)
|
|
132
|
-
net-imap (0.6.
|
|
132
|
+
net-imap (0.6.6)
|
|
133
133
|
date
|
|
134
134
|
net-protocol
|
|
135
135
|
net-pop (0.1.2)
|
|
@@ -148,7 +148,7 @@ GEM
|
|
|
148
148
|
puma (5.6.5)
|
|
149
149
|
nio4r (~> 2.0)
|
|
150
150
|
racc (1.6.0)
|
|
151
|
-
rack (2.2.
|
|
151
|
+
rack (2.2.24)
|
|
152
152
|
rack-test (2.0.2)
|
|
153
153
|
rack (>= 1.3)
|
|
154
154
|
rails (7.0.4)
|
|
@@ -235,7 +235,7 @@ GEM
|
|
|
235
235
|
warden (1.2.9)
|
|
236
236
|
rack (>= 2.0.9)
|
|
237
237
|
websocket (1.2.9)
|
|
238
|
-
websocket-driver (0.8.
|
|
238
|
+
websocket-driver (0.8.2)
|
|
239
239
|
base64
|
|
240
240
|
websocket-extensions (>= 0.1.0)
|
|
241
241
|
websocket-extensions (0.1.5)
|
|
@@ -247,6 +247,7 @@ PLATFORMS
|
|
|
247
247
|
arm64-darwin-21
|
|
248
248
|
arm64-darwin-22
|
|
249
249
|
arm64-darwin-23
|
|
250
|
+
arm64-darwin-25
|
|
250
251
|
x86_64-linux
|
|
251
252
|
|
|
252
253
|
DEPENDENCIES
|
data/README.md
CHANGED
|
@@ -2489,6 +2489,14 @@ These automatic pickups for partials are detected at build time. This means that
|
|
|
2489
2489
|
|
|
2490
2490
|
# VERSION HISTORY
|
|
2491
2491
|
|
|
2492
|
+
#### 2026-08-22 - v0.7.8
|
|
2493
|
+
- fix for time field output when no user is present (in gd mode)
|
|
2494
|
+
- 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
|
|
2495
|
+
|
|
2496
|
+
|
|
2497
|
+
#### 2026-06-01 - v0.7.7
|
|
2498
|
+
- Dynamic blocks (denoted with **) now use fully namespaced paths when rendering, this avoid out of scope issues when an action was used accross controllers
|
|
2499
|
+
|
|
2492
2500
|
#### 2026-04-08 - v0.7.6.2
|
|
2493
2501
|
- Syntax fix in code, no functional changes
|
|
2494
2502
|
|
|
@@ -57,7 +57,7 @@ module HotGlue
|
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def formatted_time_display(object, method, current_user)
|
|
60
|
-
tz = ActiveSupport::TimeZone[current_user.timezone]
|
|
60
|
+
tz = current_user.try(:timezone) ? ActiveSupport::TimeZone[current_user.timezone] : ActiveSupport::TimeZone['UTC']
|
|
61
61
|
|
|
62
62
|
t = object.public_send(method)
|
|
63
63
|
|
|
@@ -78,9 +78,10 @@ module HotGlue
|
|
|
78
78
|
end
|
|
79
79
|
|
|
80
80
|
def formatted_time_field(object, method, current_user)
|
|
81
|
-
tz = ActiveSupport::TimeZone[current_user.timezone]
|
|
81
|
+
tz = current_user.try(:timezone) ? ActiveSupport::TimeZone[current_user.timezone] : ActiveSupport::TimeZone['UTC']
|
|
82
82
|
|
|
83
83
|
t = object.public_send(method)
|
|
84
|
+
return nil if t.nil?
|
|
84
85
|
|
|
85
86
|
# Build UTC datetime from the stored time
|
|
86
87
|
utc_datetime = Time.utc(
|
|
@@ -45,7 +45,7 @@ class AssociationField < Field
|
|
|
45
45
|
if which_partial == :update_show_only && update_show_only.include?(name)
|
|
46
46
|
|
|
47
47
|
else
|
|
48
|
-
" #{name}_selector = find(\"[name='#{singular}[#{name}]']\")
|
|
48
|
+
" #{name}_selector = find(\"[name='#{singular}[#{name}]']\")\n" +
|
|
49
49
|
" #{name}_selector.first('option', text: #{assoc}1.name).select_option"
|
|
50
50
|
end
|
|
51
51
|
end
|
|
@@ -10,7 +10,10 @@ class DateTimeField < Field
|
|
|
10
10
|
|
|
11
11
|
|
|
12
12
|
def spec_setup_and_change_act(which_partial = nil)
|
|
13
|
-
|
|
13
|
+
# beginning_of_minute: an html5 datetime-local input rejects (as invalid,
|
|
14
|
+
# silently blocking form submit) a value whose seconds don't match the
|
|
15
|
+
# field's precision, so keep the test value minute-aligned.
|
|
16
|
+
" " + "new_#{name} = DateTime.current.beginning_of_minute + 1.year \n" +
|
|
14
17
|
' ' + "find(\"[name='#{testing_name}[#{ name.to_s }]']\").fill_in(with: new_#{name.to_s})"
|
|
15
18
|
|
|
16
19
|
end
|
|
@@ -24,7 +27,9 @@ class DateTimeField < Field
|
|
|
24
27
|
end
|
|
25
28
|
|
|
26
29
|
def spec_setup_let_arg
|
|
27
|
-
|
|
30
|
+
# minute-aligned so the rendered datetime-local edit field is valid when
|
|
31
|
+
# the spec fills it (see spec_setup_and_change_act)
|
|
32
|
+
"#{name}: DateTime.current.beginning_of_minute + 1.day"
|
|
28
33
|
end
|
|
29
34
|
|
|
30
35
|
def spec_list_view_assertion
|
|
@@ -5,12 +5,12 @@ class TimeField < Field
|
|
|
5
5
|
end
|
|
6
6
|
|
|
7
7
|
def form_field_output
|
|
8
|
-
"<%= time_field_localized(f, :#{name}, formatted_time_field(#{singular}, :#{name}, current_user), label: \"#{ name.to_s.humanize } \#{ current_user.timezone }\") %>"
|
|
8
|
+
"<%= time_field_localized(f, :#{name}, formatted_time_field(#{singular}, :#{name}, try(:current_user)), label: \"#{ name.to_s.humanize } \#{ try(:current_user).try(:timezone) }\") %>"
|
|
9
9
|
end
|
|
10
10
|
|
|
11
11
|
def line_field_output
|
|
12
12
|
"\n <% unless #{singular}.#{name}.nil? %>
|
|
13
|
-
<%= formatted_time_display(#{singular}, :#{name}, current_user) %>
|
|
13
|
+
<%= formatted_time_display(#{singular}, :#{name}, try(:current_user)) %>
|
|
14
14
|
<% else %>
|
|
15
15
|
<span class=''>MISSING</span>
|
|
16
16
|
<% end %>\n"
|
|
@@ -1437,12 +1437,16 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1437
1437
|
|
|
1438
1438
|
|
|
1439
1439
|
def datetime_fields_list
|
|
1440
|
-
|
|
1440
|
+
# build the hash literal as a string explicitly rather than interpolating a
|
|
1441
|
+
# live Ruby Hash into the template: Hash#inspect renders symbol keys as
|
|
1442
|
+
# `:k=>v` on Ruby <= 3.3 but `k: v` on Ruby 3.4+, so relying on it made the
|
|
1443
|
+
# generated controller's syntax depend on the host app's Ruby version.
|
|
1444
|
+
pairs = @columns.filter_map do |col|
|
|
1441
1445
|
column = @the_object.columns_hash[col.to_s]
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
end
|
|
1446
|
+
next unless column && [:datetime, :time].include?(column.type)
|
|
1447
|
+
"#{col}: :#{column.type}"
|
|
1445
1448
|
end
|
|
1449
|
+
"{#{pairs.join(', ')}}"
|
|
1446
1450
|
end
|
|
1447
1451
|
|
|
1448
1452
|
|
|
@@ -1699,6 +1703,28 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1699
1703
|
|
|
1700
1704
|
end
|
|
1701
1705
|
end
|
|
1706
|
+
|
|
1707
|
+
remove_stale_html_new_edit_views
|
|
1708
|
+
end
|
|
1709
|
+
|
|
1710
|
+
# When new/edit are served as turbo_stream we no longer generate the classic
|
|
1711
|
+
# html new.erb / edit.erb pages. A host app previously built by an older Hot
|
|
1712
|
+
# Glue would still have those stale files on disk; clean them out on
|
|
1713
|
+
# re-generation so the app doesn't keep serving (or fall back to) them.
|
|
1714
|
+
def remove_stale_html_new_edit_views
|
|
1715
|
+
return if @specs_only
|
|
1716
|
+
return unless turbo_stream_new_and_edit?
|
|
1717
|
+
|
|
1718
|
+
stale_views = []
|
|
1719
|
+
stale_views << 'new' unless @no_create
|
|
1720
|
+
stale_views << 'edit' unless @no_edit
|
|
1721
|
+
|
|
1722
|
+
stale_views.each do |view|
|
|
1723
|
+
dest_filename = cc_filename_with_extensions("#{view}", "#{@markup}")
|
|
1724
|
+
dest_filepath = File.join("#{filepath_prefix}app/views#{namespace_with_dash}",
|
|
1725
|
+
@controller_build_folder, dest_filename)
|
|
1726
|
+
remove_file dest_filepath if File.exist?(dest_filepath)
|
|
1727
|
+
end
|
|
1702
1728
|
end
|
|
1703
1729
|
|
|
1704
1730
|
def append_model_callbacks
|
|
@@ -1767,15 +1793,25 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1767
1793
|
@namespace ? "#{@namespace}/" : ""
|
|
1768
1794
|
end
|
|
1769
1795
|
|
|
1796
|
+
# new & edit are served as turbo_stream (frame replace) rather than as
|
|
1797
|
+
# standalone html pages, EXCEPT in --big-edit mode (edit is a full page)
|
|
1798
|
+
# and --display-edit-after-create mode (create redirects to the html edit
|
|
1799
|
+
# page). In those modes we keep the classic html new.erb / edit.erb views.
|
|
1800
|
+
def turbo_stream_new_and_edit?
|
|
1801
|
+
!@big_edit && !@display_edit_after_create
|
|
1802
|
+
end
|
|
1803
|
+
|
|
1770
1804
|
def all_views
|
|
1771
1805
|
res = %w(index _line _list _show)
|
|
1772
1806
|
|
|
1773
1807
|
unless @no_create
|
|
1774
|
-
res += %w(
|
|
1808
|
+
res += %w(_new_form _new_button)
|
|
1809
|
+
res << 'new' unless turbo_stream_new_and_edit?
|
|
1775
1810
|
end
|
|
1776
1811
|
|
|
1777
1812
|
unless @no_edit
|
|
1778
|
-
res
|
|
1813
|
+
res << '_edit'
|
|
1814
|
+
res << 'edit' unless turbo_stream_new_and_edit?
|
|
1779
1815
|
end
|
|
1780
1816
|
|
|
1781
1817
|
if !(@no_edit && @no_create)
|
|
@@ -1801,6 +1837,7 @@ class HotGlue::ScaffoldGenerator < Erb::Generators::ScaffoldGenerator
|
|
|
1801
1837
|
|
|
1802
1838
|
unless @no_create
|
|
1803
1839
|
res << 'create'
|
|
1840
|
+
res << 'new' if turbo_stream_new_and_edit?
|
|
1804
1841
|
end
|
|
1805
1842
|
|
|
1806
1843
|
unless @no_edit
|
|
@@ -5,4 +5,11 @@ def login_as(user)
|
|
|
5
5
|
fill_in 'Password', with: 'password'
|
|
6
6
|
end
|
|
7
7
|
click_button 'Log in'
|
|
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
|
+
expect(page).to have_content("Signed in successfully")
|
|
8
15
|
end
|
|
@@ -105,7 +105,10 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
105
105
|
authorize @<%= singular %><% elsif @pundit && @pundit_policy_override %>
|
|
106
106
|
skip_authorization
|
|
107
107
|
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.new?<% end %>
|
|
108
|
-
@action = 'new'
|
|
108
|
+
@action = 'new'<% if turbo_stream_new_and_edit? %>
|
|
109
|
+
respond_to do |format|
|
|
110
|
+
format.turbo_stream
|
|
111
|
+
end<% else %> <% end %><% if @pundit %>
|
|
109
112
|
rescue Pundit::NotAuthorizedError
|
|
110
113
|
flash[:alert] = 'You are not authorized to perform this action.'
|
|
111
114
|
load_all_<%= plural %>
|
|
@@ -181,7 +184,9 @@ class <%= controller_class_name %> < <%= controller_descends_from %>
|
|
|
181
184
|
skip_authorization
|
|
182
185
|
raise Pundit::NotAuthorizedError if ! <%= @pundit_policy_override %>.edit?<% end %>
|
|
183
186
|
@action = 'edit'
|
|
184
|
-
|
|
187
|
+
<% if turbo_stream_new_and_edit? %>respond_to do |format|
|
|
188
|
+
format.turbo_stream
|
|
189
|
+
end<% else %>render :edit<% end %><% if @pundit %>
|
|
185
190
|
rescue Pundit::NotAuthorizedError
|
|
186
191
|
flash[:notice] = "Editing <%= singular + ' ' if @include_object_names %>#{@<%= singular %>.<%= display_class %>} not authorized."
|
|
187
192
|
render :index <% end %>
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
<\%= turbo_frame_tag "<%= @namespace %>__<%= singular %>-new" do %>
|
|
2
2
|
<div>
|
|
3
|
-
<\%= link_to "<%= @new_button_label %>", <%= new_path_name %>, disable_with: "Loading...", class: "new-<%= singular %>-button btn btn-primary pull-right <%= 'btn-sm' if @nested_set.any? %> " %>
|
|
3
|
+
<\%= link_to "<%= @new_button_label %>", <%= new_path_name %>, disable_with: "Loading...", class: "new-<%= singular %>-button btn btn-primary pull-right <%= 'btn-sm' if @nested_set.any? %> "<% if turbo_stream_new_and_edit? %>, data: { turbo_stream: true }<% end %> %>
|
|
4
4
|
</div>
|
|
5
5
|
<\% end %>
|
|
@@ -42,6 +42,6 @@
|
|
|
42
42
|
<% end %>
|
|
43
43
|
|
|
44
44
|
<% unless @no_edit %>
|
|
45
|
-
<\%= link_to "Edit <% if @button_icons == 'font-awesome' %><i class='fa fa-1x fa-list-alt'></i><% end %>".html_safe, <%= edit_path_helper %> + (params[:page] ? "?page=#{params[:page]}" : ""), <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary btn-sm" %>
|
|
45
|
+
<\%= link_to "Edit <% if @button_icons == 'font-awesome' %><i class='fa fa-1x fa-list-alt'></i><% end %>".html_safe, <%= edit_path_helper %> + (params[:page] ? "?page=#{params[:page]}" : ""), <% if @big_edit %>'data-turbo' => 'false', <% end %>disable_with: "Loading...", class: "edit-<%= singular %>-button btn btn-primary btn-sm"<% if turbo_stream_new_and_edit? %>, data: { turbo_stream: true }<% end %> %>
|
|
46
46
|
<% end %>
|
|
47
47
|
</div>
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
<\%= turbo_stream.replace "<%= @namespace %>__#{dom_id(@<%= singular %>)}" do %>
|
|
2
|
-
<\%= render 'edit', locals: { <%= singular %>: @<%= singular %><%= @nested_set.collect{|arg| ", #{arg[:singular]}: @#{arg[:singular]} " }.join("") %> } %>
|
|
2
|
+
<\%= render partial: 'edit', locals: { <%= singular %>: @<%= singular %><%= @nested_set.collect{|arg| ", #{arg[:singular]}: @#{arg[:singular]} " }.join("") %> } %>
|
|
3
3
|
<\% end %>
|
|
@@ -69,7 +69,7 @@ describe 'interaction for <%= controller_class_name %>' do
|
|
|
69
69
|
expect(page).to have_content("Editing #{<%= factory_testing_name %>.<%= @display_class %>.squish || "(no name)"}")
|
|
70
70
|
<%= capybara_make_updates(:update) %>
|
|
71
71
|
click_button "Save"
|
|
72
|
-
within("turbo-frame#<%= @namespace %>__#{dom_id(<%= factory_testing_name %>)}
|
|
72
|
+
within("turbo-frame#<%= @namespace %>__#{dom_id(<%= factory_testing_name %>)}") do
|
|
73
73
|
<%= " " + @columns_map.map{ |col, col_object|
|
|
74
74
|
if @attachments.keys.collect(&:to_sym).include?(col)
|
|
75
75
|
elsif @show_only.include?(col)
|
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.7.
|
|
4
|
+
version: 0.7.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-
|
|
11
|
+
date: 2026-08-22 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: rails
|
|
@@ -115,6 +115,7 @@ files:
|
|
|
115
115
|
- lib/generators/hot_glue/templates/erb/edit.turbo_stream.erb
|
|
116
116
|
- lib/generators/hot_glue/templates/erb/index.erb
|
|
117
117
|
- lib/generators/hot_glue/templates/erb/new.erb
|
|
118
|
+
- lib/generators/hot_glue/templates/erb/new.turbo_stream.erb
|
|
118
119
|
- lib/generators/hot_glue/templates/erb/update.turbo_stream.erb
|
|
119
120
|
- lib/generators/hot_glue/templates/javascript/date_range_picker_controller.js
|
|
120
121
|
- lib/generators/hot_glue/templates/javascript/dropzone_controller.js
|
|
@@ -164,7 +165,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
164
165
|
- !ruby/object:Gem::Version
|
|
165
166
|
version: '0'
|
|
166
167
|
requirements: []
|
|
167
|
-
rubygems_version: 3.
|
|
168
|
+
rubygems_version: 3.5.22
|
|
168
169
|
signing_key:
|
|
169
170
|
specification_version: 4
|
|
170
171
|
summary: A gem to build Turbo Rails scaffolding.
|