render_turbo_stream 0.1.9 → 0.1.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 +4 -4
- data/README.md +75 -21
- data/app/controllers/render_turbo_stream/application_controller.rb +4 -0
- data/app/views/render_turbo_stream_partials.turbo_stream.erb +52 -0
- data/app/views/render_turbo_stream_redirect.turbo_stream.erb +1 -0
- data/lib/render_turbo_stream/engine.rb +5 -0
- data/lib/render_turbo_stream/version.rb +1 -1
- data/lib/render_turbo_stream.rb +155 -5
- metadata +11 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aa9b9cefa95d380af39fd2f096f569cb4eabe94fe024164722cae8497b7d076f
|
4
|
+
data.tar.gz: 9973fe128954730c6b1dc9f52ecc63a6b633951d118f06eae0e2672c54a519d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 1738911b840851ed5d3974702bea36029f8bcb453786b5524bef7c1f2fee0ee78dccfc0f275e8e5f72b724f787425aa13f821c7c251c5ad92876c5c728b2bad5
|
7
|
+
data.tar.gz: 6be68eb76a040ab06fb97380d80d03ce16e55096819062a5c8760604a5d9df5808ba1c72229afe7a9807e9ec6c6e69a305b17be2a94ed110eae4ec8461c148cd
|
data/README.md
CHANGED
@@ -1,58 +1,110 @@
|
|
1
1
|
# RenderTurboStream
|
2
2
|
|
3
|
-
|
3
|
+
The machine gun for your turbo-stream partials.
|
4
4
|
|
5
|
-
|
5
|
+
Creating a gem from this is in work, see [rails issue](https://github.com/rails/rails/issues/47954)
|
6
6
|
|
7
|
-
|
7
|
+
Defining templates like `update.turbo_stream.haml` annoyed me.
|
8
8
|
|
9
|
-
|
9
|
+
Working consistently by turbo_stream means: shooting many partials to the frontend which always needs the same attributes: ID, partial and maybe some locals. This gem serializes that: Partials can be steered directly from the controller.
|
10
10
|
|
11
|
-
|
11
|
+
Currently it is only possible by copy and paste the code, see below.
|
12
12
|
|
13
13
|
## Installation
|
14
14
|
|
15
|
-
|
15
|
+
```ruby
|
16
|
+
gem 'render_turbo_stream'
|
17
|
+
```
|
16
18
|
|
17
|
-
|
19
|
+
```shell
|
20
|
+
bundle install
|
21
|
+
```
|
18
22
|
|
19
|
-
|
23
|
+
**ApplicationController**
|
20
24
|
|
21
|
-
|
25
|
+
```ruby
|
26
|
+
include RenderTurboStream
|
27
|
+
```
|
22
28
|
|
23
29
|
The corresponding partials for flashes could look [like this](https://gitlab.com/sedl/renderturbostream/-/wikis/flashes)
|
24
30
|
|
25
31
|
## Usage
|
26
32
|
|
33
|
+
`turbo_stream_save` is a special method for streamline `update` or `create` functions for `turbo_stream`, which could look like so:
|
34
|
+
|
27
35
|
```ruby
|
28
36
|
def create
|
29
37
|
@customer = Customer.new(customer_params)
|
30
38
|
|
31
|
-
|
39
|
+
turbo_stream_save(
|
32
40
|
@customer.save,
|
33
|
-
redirect_on_success_to: edit_customer_path(@customer)
|
34
|
-
id: 'customer-form-wrapper',
|
35
|
-
partial: 'customer_form',
|
41
|
+
redirect_on_success_to: edit_customer_path(@customer)
|
36
42
|
)
|
37
43
|
|
38
44
|
end
|
39
45
|
```
|
40
46
|
|
41
|
-
and
|
47
|
+
This sets a status, generates a flash message and performs `stream_partials`, which could result like that:
|
48
|
+
|
49
|
+
```ruby
|
50
|
+
stream_partials(
|
51
|
+
[
|
52
|
+
{
|
53
|
+
id: 'form',
|
54
|
+
partial: 'form'
|
55
|
+
},
|
56
|
+
{
|
57
|
+
id: 'flash-wrapper',
|
58
|
+
partial: 'layouts/flashes',
|
59
|
+
action: :prepend
|
60
|
+
}
|
61
|
+
]
|
62
|
+
)
|
63
|
+
```
|
64
|
+
|
65
|
+
The `stream_partial` method is nothing else than a singular of `stream_partials`
|
42
66
|
|
43
|
-
|
67
|
+
```ruby
|
68
|
+
stream_partial(
|
69
|
+
id,
|
70
|
+
partial: nil, #=> default: id.gsub('-','_')
|
71
|
+
locals: {},
|
72
|
+
action: nil #=> default: :replace
|
73
|
+
)
|
74
|
+
```
|
44
75
|
|
45
76
|
## Testing
|
46
77
|
|
47
|
-
|
78
|
+
For system testing you need capybara.
|
48
79
|
|
49
|
-
|
80
|
+
For enabling request specs:
|
50
81
|
|
51
|
-
|
82
|
+
If `request.format` is not `turbo_stream` the method responds as `json` with status.
|
83
|
+
`response.body` returns a `json` where the key is the `html-ID` that is used by turbo-stream with the properties of the partials. Testing by rspec could look like this:
|
52
84
|
|
53
|
-
|
85
|
+
```ruby
|
86
|
+
it 'update failed' do
|
87
|
+
a = FactoryBot.create(:article)
|
88
|
+
patch article_path(a, params: invalid_params)
|
89
|
+
expect(response.status).to eq(422)
|
90
|
+
h = JSON.parse(response.body)
|
91
|
+
expect(h['form']['partial']).to eq('articles/form')
|
92
|
+
expect(h['flash-box']['partial']).to eq('layouts/flash')
|
93
|
+
expect(h.keys.length).to eq(2)
|
94
|
+
end
|
95
|
+
```
|
54
96
|
|
55
|
-
|
97
|
+
Test for a redirection could look like this:
|
98
|
+
|
99
|
+
```ruby
|
100
|
+
it 'update success' do
|
101
|
+
a = FactoryBot.create(:article)
|
102
|
+
patch article_path(a, params: valid_params)
|
103
|
+
expect(response.status).to eq(302)
|
104
|
+
r = JSON.parse(response.body)
|
105
|
+
expect(r['redirected_to']).to eq(articles_path)
|
106
|
+
end
|
107
|
+
```
|
56
108
|
|
57
109
|
## Parameters
|
58
110
|
|
@@ -84,7 +136,7 @@ Save Action failed: `422` `:unprocessable_entity`
|
|
84
136
|
|
85
137
|
gem `turbo_power` (is included, used for redirection)
|
86
138
|
|
87
|
-
**Translations
|
139
|
+
**Translations**
|
88
140
|
|
89
141
|
`activerecord.success.successfully_created`
|
90
142
|
|
@@ -94,6 +146,8 @@ gem `turbo_power` (is included, used for redirection)
|
|
94
146
|
|
95
147
|
`activerecord.errors.messages.could_not_update`
|
96
148
|
|
149
|
+
example value: `"%<model_name>s successfully created"`
|
150
|
+
|
97
151
|
.. and Model Name Translations
|
98
152
|
|
99
153
|
**Flash configuration**
|
@@ -0,0 +1,52 @@
|
|
1
|
+
<% error = false %>
|
2
|
+
<% control = [] %>
|
3
|
+
<% local_assigns[:streams].each do |s| %>
|
4
|
+
<% ctl = { partial: s[:partial], id: s[:id] } %>
|
5
|
+
<% info = { id: s[:id], partial: s[:partial], locals: s[:locals] } %>
|
6
|
+
|
7
|
+
<% if !s[:id] %>
|
8
|
+
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => MISSING ID => #{s}") %>
|
9
|
+
<% error = true %>
|
10
|
+
|
11
|
+
<% elsif !s[:partial].present? %>
|
12
|
+
<% Rails.logger.error(" ERROR RENDER TURBO STREAM => MISSING PARTIAL => #{s}") %>
|
13
|
+
<% error = true %>
|
14
|
+
<% ctl[:partial] = nil %>
|
15
|
+
|
16
|
+
<% elsif s[:action].to_sym == :replace %>
|
17
|
+
<% ctl[:action] = :replace %>
|
18
|
+
<% Rails.logger.debug(" • render-turbo-stream REPLACE => #{info}") %>
|
19
|
+
<%= turbo_stream.replace s[:id] do %>
|
20
|
+
<%= render s[:partial], locals: s[:locals] %>
|
21
|
+
<% end %>
|
22
|
+
|
23
|
+
<% elsif s[:action].to_sym == :prepend %>
|
24
|
+
<% ctl[:action] = :prepend %>
|
25
|
+
<% Rails.logger.debug(" • render-turbo-stream PREPEND => #{info}") %>
|
26
|
+
<%= turbo_stream.prepend s[:id] do %>
|
27
|
+
<%= render s[:partial], locals: s[:locals] %>
|
28
|
+
<% end %>
|
29
|
+
|
30
|
+
<% elsif s[:action].to_sym == :append %>
|
31
|
+
<% ctl[:action] = :append %>
|
32
|
+
<% Rails.logger.debug(" • render-turbo-stream APPEND => #{info}") %>
|
33
|
+
<%= turbo_stream.prepend s[:id] do %>
|
34
|
+
<%= render s[:partial], locals: s[:locals] %>
|
35
|
+
<% end %>
|
36
|
+
|
37
|
+
<% else %>
|
38
|
+
<% ctl[:action] = :UNKNOWN %>
|
39
|
+
<% Rails.logger.fatal(" ERROR render-turbo-stream => UNKNOWN ACTION => #{s}") %>
|
40
|
+
<% error = true %>
|
41
|
+
<% end %>
|
42
|
+
|
43
|
+
<% control.push(ctl) %>
|
44
|
+
|
45
|
+
<% end %>
|
46
|
+
|
47
|
+
<% if error %>
|
48
|
+
<% Rails.logger.error(" RENDER TURBO STREAM HAD ERRORS, REPEATING WHOLE ARRAY: ") %>
|
49
|
+
<% control.each do |c| %>
|
50
|
+
<% Rails.logger.error(" #{c}") %>
|
51
|
+
<% end %>
|
52
|
+
<% end %>
|
@@ -0,0 +1 @@
|
|
1
|
+
<%= turbo_stream.redirect_to local_assigns[:url] %>
|
data/lib/render_turbo_stream.rb
CHANGED
@@ -1,12 +1,162 @@
|
|
1
1
|
require "render_turbo_stream/version"
|
2
2
|
require "render_turbo_stream/railtie"
|
3
|
+
require 'render_turbo_stream/engine'
|
3
4
|
|
4
5
|
module RenderTurboStream
|
5
|
-
|
6
|
-
def
|
7
|
-
|
8
|
-
|
9
|
-
|
6
|
+
|
7
|
+
def turbo_stream_save(
|
8
|
+
save_action,
|
9
|
+
redirect_on_success_to: nil,
|
10
|
+
object: nil,
|
11
|
+
id: 'form', # if nil: no partial is rendered
|
12
|
+
partial: nil, # default: same like ID
|
13
|
+
action: 'replace',
|
14
|
+
locals: {},
|
15
|
+
streams_on_success: [
|
16
|
+
{
|
17
|
+
id: nil,
|
18
|
+
partial: 'form',
|
19
|
+
locals: {},
|
20
|
+
action: 'replace'
|
21
|
+
}
|
22
|
+
],
|
23
|
+
streams_on_error: [
|
24
|
+
{
|
25
|
+
id: nil,
|
26
|
+
partial: 'form',
|
27
|
+
locals: {},
|
28
|
+
action: 'replace'
|
29
|
+
}
|
30
|
+
],
|
31
|
+
add_flash_alerts: [], #=> array of strings
|
32
|
+
add_flash_notices: [], #=> array of strings
|
33
|
+
flashes_on_success: [], #=> array of strings
|
34
|
+
flashes_on_error: [] #=> array of strings
|
35
|
+
)
|
36
|
+
|
37
|
+
unless object
|
38
|
+
object = eval("@#{controller_name.classify.underscore}")
|
39
|
+
end
|
40
|
+
|
41
|
+
#== Streams / Partials
|
42
|
+
|
43
|
+
streams = [(id ? { id: id, partial: partial, locals: locals, action: action } : nil)]
|
44
|
+
|
45
|
+
if save_action
|
46
|
+
response.status = 200
|
47
|
+
streams += streams_on_success.select { |s| s[:id].present? }
|
48
|
+
else
|
49
|
+
response.status = :unprocessable_entity
|
50
|
+
streams += streams_on_error.select { |s| s[:id].present? }
|
51
|
+
end
|
52
|
+
|
53
|
+
#== FLASHES
|
54
|
+
|
55
|
+
model_name = object.model_name.human
|
56
|
+
if save_action
|
57
|
+
flash_notices = if flashes_on_success.present?
|
58
|
+
flashes_on_success
|
59
|
+
elsif action_name == 'create'
|
60
|
+
[format(I18n.t('activerecord.success.successfully_created'), model_name: model_name)]
|
61
|
+
elsif action_name == 'update'
|
62
|
+
[format(I18n.t('activerecord.success.successfully_updated'), model_name: model_name)]
|
63
|
+
end
|
64
|
+
flash_alerts = []
|
65
|
+
else
|
66
|
+
flash_alerts = if flashes_on_error.present?
|
67
|
+
flashes_on_error
|
68
|
+
elsif action_name == 'create'
|
69
|
+
[format(I18n.t('activerecord.errors.messages.could_not_create'), model_name: model_name)]
|
70
|
+
elsif action_name == 'update'
|
71
|
+
[format(I18n.t('activerecord.errors.messages.could_not_update'), model_name: model_name)]
|
72
|
+
end
|
73
|
+
flash_notices = []
|
74
|
+
end
|
75
|
+
flash_notices += add_flash_notices
|
76
|
+
flash_alerts += add_flash_alerts
|
77
|
+
_flash_id = Rails.configuration.x.render_turbo_stream.flash_id
|
78
|
+
flash_id = (_flash_id ? _flash_id : "ERROR, MISSING CONFIG => config.x.render_turbo_stream.flash_id")
|
79
|
+
flash_partial = Rails.configuration.x.render_turbo_stream.flash_partial
|
80
|
+
flash_action = Rails.configuration.x.render_turbo_stream.flash_action
|
81
|
+
flash_notices.each do |notice|
|
82
|
+
# inside the flash partial has to be a loop that handles all theese flashes
|
83
|
+
flash_stream = {
|
84
|
+
id: flash_id,
|
85
|
+
partial: flash_partial,
|
86
|
+
action: flash_action,
|
87
|
+
locals: { success: true, message: notice }
|
88
|
+
}
|
89
|
+
streams.push(flash_stream)
|
90
|
+
end
|
91
|
+
flash_alerts.each do |alert|
|
92
|
+
# inside the flash partial has to be a loop that handles all theese flashes
|
93
|
+
flash_stream = {
|
94
|
+
id: flash_id,
|
95
|
+
partial: flash_partial,
|
96
|
+
action: flash_action,
|
97
|
+
locals: { success: false, message: alert }
|
98
|
+
}
|
99
|
+
streams.push(flash_stream)
|
10
100
|
end
|
101
|
+
|
102
|
+
#== render
|
103
|
+
|
104
|
+
if save_action && redirect_on_success_to.present?
|
105
|
+
response.status = 302
|
106
|
+
flash[:alert] = flash_alerts
|
107
|
+
flash[:notice] = flash_notices
|
108
|
+
if request.format.to_sym == :turbo_stream
|
109
|
+
render template: 'render_turbo_stream_redirect', locals: { url: redirect_on_success_to }, layout: false
|
110
|
+
else
|
111
|
+
render json: { redirected_to: redirect_on_success_to }
|
112
|
+
end
|
113
|
+
else
|
114
|
+
flash.now[:alert] = flash_alerts
|
115
|
+
flash.now[:notice] = flash_notices
|
116
|
+
stream_partials(streams)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def stream_partials(array)
|
121
|
+
|
122
|
+
ary = []
|
123
|
+
array.dup.each do |props|
|
124
|
+
part = (props[:partial].present? ? props[:partial] : props[:id]).gsub('-', '_')
|
125
|
+
partial = (part.to_s.include?('/') ? part : [controller_path, part].join('/'))
|
126
|
+
r = props
|
127
|
+
r[:action] = (props[:action].present? ? props[:action] : :replace)
|
128
|
+
r[:partial] = partial
|
129
|
+
ary.push(r)
|
130
|
+
end
|
131
|
+
|
132
|
+
if request.format.to_sym == :turbo_stream
|
133
|
+
render template: 'render_turbo_stream_partials', locals: { streams: ary }, layout: false
|
134
|
+
else
|
135
|
+
check = {}
|
136
|
+
ary.each do |a|
|
137
|
+
b = a.dup
|
138
|
+
b.delete(:id)
|
139
|
+
check[a[:id]] = b
|
140
|
+
end
|
141
|
+
render json: check
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
def stream_partial(
|
146
|
+
id,
|
147
|
+
partial: nil, #=> default: id
|
148
|
+
action: :replace,
|
149
|
+
locals: {}
|
150
|
+
)
|
151
|
+
stream_partials(
|
152
|
+
[
|
153
|
+
{
|
154
|
+
id: id,
|
155
|
+
partial: partial,
|
156
|
+
action: action,
|
157
|
+
locals: locals
|
158
|
+
}
|
159
|
+
]
|
160
|
+
)
|
11
161
|
end
|
12
162
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: render_turbo_stream
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.12
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- christian
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2023-04-
|
11
|
+
date: 2023-04-17 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rails
|
@@ -24,7 +24,10 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: 7.0.4.3
|
27
|
-
description: '
|
27
|
+
description: 'Writing views like (create|update).turbo_stream.haml annoyed me. This
|
28
|
+
gem handles translated flash messages, set status and renders turbo-stream partials.
|
29
|
+
You can steer your turbo-stream partials directly from the contoller. It also handles
|
30
|
+
redirection: turbo_power is included.'
|
28
31
|
email:
|
29
32
|
- christian@sedlmair.ch
|
30
33
|
executables: []
|
@@ -33,7 +36,11 @@ extra_rdoc_files: []
|
|
33
36
|
files:
|
34
37
|
- README.md
|
35
38
|
- Rakefile
|
39
|
+
- app/controllers/render_turbo_stream/application_controller.rb
|
40
|
+
- app/views/render_turbo_stream_partials.turbo_stream.erb
|
41
|
+
- app/views/render_turbo_stream_redirect.turbo_stream.erb
|
36
42
|
- lib/render_turbo_stream.rb
|
43
|
+
- lib/render_turbo_stream/engine.rb
|
37
44
|
- lib/render_turbo_stream/railtie.rb
|
38
45
|
- lib/render_turbo_stream/version.rb
|
39
46
|
- lib/tasks/render_turbo_stream_tasks.rake
|
@@ -62,5 +69,5 @@ requirements: []
|
|
62
69
|
rubygems_version: 3.4.12
|
63
70
|
signing_key:
|
64
71
|
specification_version: 4
|
65
|
-
summary:
|
72
|
+
summary: Rendering turbo-stream partials directly from controller
|
66
73
|
test_files: []
|