首页 > 解决方案 > Rails 6.1 在渲染时重定向到 json 页面

问题描述

我有一种情况,我正在使用频道发布评论,并且在将 rails 更新到 6.1 时,我遇到了一个奇怪的错误。创建方法如下所示

def create
    offer = Offer.find(comment_params[:offer_id])

    @comment = Comment.new(
      user_id: current_user.id,
      offer_id: offer.id,
      content: comment_params[:content],
      attachment_file: comment_params[:attachment_file]
    )

    if @comment.save
      CommentChannel.broadcast_to offer, message: render_comment(@comment)
      render json: { success: true }
    else
      render json: { success: true }
    end
  end

render_comment方法如下

def render_comment(comment)
    render_to_string(partial: "offers/comment", locals: {comment: comment}, layout: false)
end

这是按原样工作的,但现在每当我创建新评论时,它都会突然重定向到此页面

在此处输入图像描述

评论被创建,除了这个随机重定向之外,一切似乎都正常工作。这可能是什么原因?我以为它与render_to_string,但无法弄清楚。

这里也是表格

<%= form_with model: Comment.new, id: 'new-comment' do |f| %>
 <%= f.hidden_field :offer_id, value: @offer.id %>
 <div>
 <%= f.text_area :content %>
 <div class="mt-3 flex items-center justify-between">
  <%= f.submit "Comment", id:"comment-button",%>
 </div>
<% end %>

标签: ruby-on-rails

解决方案


您看到的不是重定向。您正在发送一个非 XHR 请求,并且服务器正在返回呈现的 JSON 和一个application/json内容类型。

您可以看到它触发了浏览器中的花哨 JSON 语法高亮和格式化。

你真正想要的东西是这样的:

# POST /offers/1/comments.json
def create
  offer = Offer.find(params[:offer_id])
  comment = offer.comments.new(comment_params) do |c|
    c.user = current_user.id
  end
  if comment.save
    CommentChannel.broadcast_to offer, message: render_comment(comment)
    render json: comment,
      status: :created,
      location: comment
  else
    render json: { errors: comment.errors.full_messages },
      status: :unprocessable_entity
  end
end

# ...

private

def comment_params
  params.require(:comment)
        .permit(:content, :attachment_file)
end

这提供了一个更好的 API,您可以在集成测试中测试响应代码(您正在测试不是吗?;))而不是解析 JSON。

201 Created 响应不必在响应中包含实体,但它对于 ajax 获取新创建的对象非常有用。

您还应该嵌套路由而不是使用隐藏输入:

# routes.rb
resources :offers do
  resources :comments, only: [:create]
end
<%= form_with model: [offer, comment], 
  id: 'new-comment', 
  "data-type" => 'json', 
  remote: true do |f| %>
  <%= f.text_area :content %>
  <div class="mt-3 flex items-center justify-between">
    <%= f.submit "Comment", id:"comment-button",%>
  </div>
<% end %>

由于 Rails 6.1form_with没有默认设置,remote: true因此您可以选择加入该config.action_view.form_with_generates_remote_forms选项。Rails UJS 默认application/javascript为 XHR 请求的类型。

由于您发送了正确的响应代码,它将触发适当的 ajax 处理程序方法:

let form = document.getElementById('new-comment');

// Handle when a comment is created
form.addEventListener("ajax:success", (event) => {
  const [data, status, xhr] = event.detail;
  console.log(data); // the newly created comment
});

// Handle invalid input
form.addEventListener("ajax:error", (event) => {
  const [data, status, xhr] = event.detail;
  console.log(data.errors); // the errors
});

推荐阅读