如何首先在 broadcasts_to 中呈现部分内容然后重定向 (AbstractController::DoubleRenderError)
How to first render a partial in broadcasts_to and then redirect (AbstractController::DoubleRenderError)
我是 Rails 的新手,在数据库中保存新记录时尝试使用 Action Cable 更新客户端。
为此,我有这个 posts_controller.rb
:
# POST /posts
# POST /posts.json
def create
@post = Post.new(post_params)
picture = params[:post][:picture]
respond_to do |format|
if @post.save
@post.picture.attach(picture) if picture.present?
PostsChannel.broadcast_to @post, html: render(partial: 'post', locals: { post: @post }) #<--- render
format.html { redirect_to posts_url, notice: 'Post was successfully created.' } #<--- redirect
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
和_post.html.erb
:
<div class="cd-timeline__block js-cd-block">
<div class="cd-timeline__img cd-timeline__img--picture js-cd-img">
<p></p>
</div>
<div class="cd-timeline__content js-cd-content">
<%= image_tag post.picture.variant(resize: '400x400') %>
<p><%= post.text %></p>
<span class="cd-timeline__date"><%= post.created_at.strftime('%d/%m/%Y %T') %></span>
</div>
</div>
由于部分呈现和重定向,最终出现错误 AbstractController::DoubleRenderError
。问题是我不知道该怎么做。我不想在 JS 文件中生成 HTML,因为看到了一些代码示例(我的 post 模板会有代码重复)。我一直在寻找其他示例,但没有任何帮助。
讨论了同样的问题 and 但是我不知道如何使用 flash 来获得我想要的东西。
有什么建议吗?
您可以尝试将渲染移动到 after_action 回调吗?您将有权访问 @post
,因此您可以致电 @post.valid?
以了解是否需要广播。我不确定这是否有效,但您可以尝试一下。
不过,我不会广播部分渲染图。也许将 @post
广播为 json 并使用 javascript 客户端更新视图会更快。
编辑:尝试 render_to_string
https://apidock.com/rails/AbstractController/Rendering/render_to_string
它呈现视图和局部视图,但不设置请求的响应正文。刚在本地试过,它适用于两个渲染器。
好的,我成功了! :)
有一个 rails 函数完全符合我的要求:render_to_string 不发送 http 响应。
我在使用 websockets 时遇到了一些问题,所以我安装了 Redis + 改变了我广播的方式,现在一切正常!
作为记录,这里是全部内容:
# config/routes.rb
Rails.application.routes.draw do
resources :posts
mount ActionCable.server => '/cable'
end
-
# config/cable.yml
development:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
-
# app/channels/posts_channel.rb
class PostsChannel < ApplicationCable::Channel
def subscribed
stream_for 'post'
end
end
-
// app/assets/javascripts/channels/posts.js
App.cable.subscriptions.create('PostsChannel', {
received: function({ html }) {
$("#timeline-container").prepend(html);
}
});
-
<!-- app/views/posts/_post.html.erb -->
<div class="cd-timeline__block js-cd-block">
<div class="cd-timeline__img cd-timeline__img--picture js-cd-img">
<p></p>
</div>
<div class="cd-timeline__content js-cd-content">
<%= image_tag post.picture.variant(resize: '400x400') %>
<p><%= post.text %></p>
<span class="cd-timeline__date"><%= post.created_at.strftime('%d/%m/%Y %T') %></span>
</div>
</div>
-
# POST /posts
# POST /posts.json
def create
@post = Post.new(post_params)
picture = params[:post][:picture]
respond_to do |format|
if @post.save
@post.picture.attach(picture) if picture.present?
ActionCable.server.broadcast 'posts:post', html: render_to_string(partial: 'post', locals: { post: @post })
format.html { redirect_to posts_url, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
我是 Rails 的新手,在数据库中保存新记录时尝试使用 Action Cable 更新客户端。
为此,我有这个 posts_controller.rb
:
# POST /posts
# POST /posts.json
def create
@post = Post.new(post_params)
picture = params[:post][:picture]
respond_to do |format|
if @post.save
@post.picture.attach(picture) if picture.present?
PostsChannel.broadcast_to @post, html: render(partial: 'post', locals: { post: @post }) #<--- render
format.html { redirect_to posts_url, notice: 'Post was successfully created.' } #<--- redirect
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end
和_post.html.erb
:
<div class="cd-timeline__block js-cd-block">
<div class="cd-timeline__img cd-timeline__img--picture js-cd-img">
<p></p>
</div>
<div class="cd-timeline__content js-cd-content">
<%= image_tag post.picture.variant(resize: '400x400') %>
<p><%= post.text %></p>
<span class="cd-timeline__date"><%= post.created_at.strftime('%d/%m/%Y %T') %></span>
</div>
</div>
由于部分呈现和重定向,最终出现错误 AbstractController::DoubleRenderError
。问题是我不知道该怎么做。我不想在 JS 文件中生成 HTML,因为看到了一些代码示例(我的 post 模板会有代码重复)。我一直在寻找其他示例,但没有任何帮助。
讨论了同样的问题
有什么建议吗?
您可以尝试将渲染移动到 after_action 回调吗?您将有权访问 @post
,因此您可以致电 @post.valid?
以了解是否需要广播。我不确定这是否有效,但您可以尝试一下。
不过,我不会广播部分渲染图。也许将 @post
广播为 json 并使用 javascript 客户端更新视图会更快。
编辑:尝试 render_to_string
https://apidock.com/rails/AbstractController/Rendering/render_to_string
它呈现视图和局部视图,但不设置请求的响应正文。刚在本地试过,它适用于两个渲染器。
好的,我成功了! :)
有一个 rails 函数完全符合我的要求:render_to_string 不发送 http 响应。 我在使用 websockets 时遇到了一些问题,所以我安装了 Redis + 改变了我广播的方式,现在一切正常!
作为记录,这里是全部内容:
# config/routes.rb
Rails.application.routes.draw do
resources :posts
mount ActionCable.server => '/cable'
end
-
# config/cable.yml
development:
adapter: redis
url: <%= ENV.fetch("REDIS_URL") { "redis://localhost:6379/1" } %>
-
# app/channels/posts_channel.rb
class PostsChannel < ApplicationCable::Channel
def subscribed
stream_for 'post'
end
end
-
// app/assets/javascripts/channels/posts.js
App.cable.subscriptions.create('PostsChannel', {
received: function({ html }) {
$("#timeline-container").prepend(html);
}
});
-
<!-- app/views/posts/_post.html.erb -->
<div class="cd-timeline__block js-cd-block">
<div class="cd-timeline__img cd-timeline__img--picture js-cd-img">
<p></p>
</div>
<div class="cd-timeline__content js-cd-content">
<%= image_tag post.picture.variant(resize: '400x400') %>
<p><%= post.text %></p>
<span class="cd-timeline__date"><%= post.created_at.strftime('%d/%m/%Y %T') %></span>
</div>
</div>
-
# POST /posts
# POST /posts.json
def create
@post = Post.new(post_params)
picture = params[:post][:picture]
respond_to do |format|
if @post.save
@post.picture.attach(picture) if picture.present?
ActionCable.server.broadcast 'posts:post', html: render_to_string(partial: 'post', locals: { post: @post })
format.html { redirect_to posts_url, notice: 'Post was successfully created.' }
format.json { render :show, status: :created, location: @post }
else
format.html { render :new }
format.json { render json: @post.errors, status: :unprocessable_entity }
end
end
end