render_turbo_stream 0.1.9 → 0.1.12

Sign up to get free protection for your applications and to get access to all the features.
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: []