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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: b699433559bcb2f6c79f10a8df305584db96042dd43de7999eb17b00cf87ffc9
4
- data.tar.gz: 3c85d56f2991b7bb8676b2864caee8eb20c271161fc38d4c378d206838007648
3
+ metadata.gz: aa9b9cefa95d380af39fd2f096f569cb4eabe94fe024164722cae8497b7d076f
4
+ data.tar.gz: 9973fe128954730c6b1dc9f52ecc63a6b633951d118f06eae0e2672c54a519d2
5
5
  SHA512:
6
- metadata.gz: 243377679364d09d0c3ced284dbdcbc72be83dc0f16d18f8d54f0c2f8c71c6e2d9b613cab3e493a6a4f8454fcfa29a837da5ffc624b5c77b3399e1fa3a2cdae3
7
- data.tar.gz: ed18eee7081e7ebc1ea98fd4159d0876a1edee0116c34e4dd18362c214834dc8e37fca5af3b411f6f0bac33e86606f5f5dda6b537d3cbf529db87dafb3bdf180
6
+ metadata.gz: 1738911b840851ed5d3974702bea36029f8bcb453786b5524bef7c1f2fee0ee78dccfc0f275e8e5f72b724f787425aa13f821c7c251c5ad92876c5c728b2bad5
7
+ data.tar.gz: 6be68eb76a040ab06fb97380d80d03ce16e55096819062a5c8760604a5d9df5808ba1c72229afe7a9807e9ec6c6e69a305b17be2a94ed110eae4ec8461c148cd
data/README.md CHANGED
@@ -1,58 +1,110 @@
1
1
  # RenderTurboStream
2
2
 
3
- Creating a gem currently is not possible because of [rails issue](https://github.com/rails/rails/issues/47954)
3
+ The machine gun for your turbo-stream partials.
4
4
 
5
- So, applying this idea is currently only possible by copy and paste a method and a view, see below.
5
+ Creating a gem from this is in work, see [rails issue](https://github.com/rails/rails/issues/47954)
6
6
 
7
- Working consistently by turbo_stream means: shooting a lot of partials to the html which always needs the same attributes: ID, partial and maybe some locals. This gem is a attempt to serialize that, especially for `update` and `create` action.
7
+ Defining templates like `update.turbo_stream.haml` annoyed me.
8
8
 
9
- Logic is better placed inside the controller, instead of the view and it's boring to write always the same `ifs` inside the `update.turbo_stream.haml`. So this gem holds a `.turbo_stream.html.erb` view that loops through all the partials that should be rendered.
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
- In 90% of cases you have just define your partials, like `_form.haml` and steer them from the controller directly, without a `.turbo_stream.haml` view.
11
+ Currently it is only possible by copy and paste the code, see below.
12
12
 
13
13
  ## Installation
14
14
 
15
- Because of [that issue](https://github.com/rails/rails/issues/47954) appying this feature is currently only possible by copy and paste following files to your app
15
+ ```ruby
16
+ gem 'render_turbo_stream'
17
+ ```
16
18
 
17
- [application_controller](https://gitlab.com/sedl/renderturbostream/-/wikis/application_controller)
19
+ ```shell
20
+ bundle install
21
+ ```
18
22
 
19
- [layout/render_partials.turbo_stream.erb](https://gitlab.com/sedl/renderturbostream/-/wikis/layout/render.turbo_stream.erb)
23
+ **ApplicationController**
20
24
 
21
- [layouts/render_redirect.turbo_stream.erb](https://gitlab.com/sedl/renderturbostream/-/wikis/layouts/render_redirect.turbo_stream.erb)
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
- render_turbo_stream(
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 its done!
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
- in 90% use cases it should be enough and not necessary writing any code inside `update.turbo_stream.haml` or `create.turbo_stream.haml`
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
- Testing by regular `rspec` request specs the controller is rendering classic html templates, not turbo_stream. For that html templates are rendered, but only with hints so that your test can check which action is done.
78
+ For system testing you need capybara.
48
79
 
49
- It has 3 cases of output with its resulting status codes which can be checked by rspec:
80
+ For enabling request specs:
50
81
 
51
- Success and redirection: `302`
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
- Success without redirection: `200`
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
- Save Action failed: `422` `:unprocessable_entity`
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 used**
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,4 @@
1
+ module RenderTurboStream
2
+ class ApplicationController < ActionController::Base
3
+ end
4
+ end
@@ -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] %>
@@ -0,0 +1,5 @@
1
+ module RenderTurboStream
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace RenderTurboStream
4
+ end
5
+ end
@@ -1,3 +1,3 @@
1
1
  module RenderTurboStream
2
- VERSION = "0.1.9"
2
+ VERSION = "0.1.12"
3
3
  end
@@ -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
- # Your code goes here...
6
- def testmethod
7
- render template: 'layouts/render', layout: false
8
- respond_to do |format|
9
- format.turbo_stream { render template: 'layouts/render', layout: false }
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.9
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-15 00:00:00.000000000 Z
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: 'NOT USABLE AS GEM see: Homepage / README'
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: 'NOT USABLE AS GEM see: Homepage / README'
72
+ summary: Rendering turbo-stream partials directly from controller
66
73
  test_files: []