Ruby on Rails: Figuring out 406 error / lack of redirect with AJAXified form

时间:2022-08-28 08:52:51

I have a project with an "Article" scaffold - which includes a paperclip file field for the thumbnail - and others on the team are complaining about how they have to add the file to the field again when they submit the form and a validation error is triggered due to missing data on another field.

我有一个带有“文章”脚手架的项目 - 其中包含缩略图的回形针文件字段 - 团队中的其他人正在抱怨他们在提交表单时如何将文件再次添加到字段中,并且验证错误是由于另一个字段上的数据丢失而触发

Figuring that was due to browser limitations, I added a remote => true to the form, along with an error.js.erb file, figuring the file field would persist if the page didn't have to be reloaded. Unfortunately that wasn't the case, as I read that browsers are unable to process multipart forms / files through AJAX for security reasons. However, I then discovered the Remotipart gem which solves this issue. So the relevant parts of my application looks like the following...

确定这是由于浏览器的限制,我在表单中添加了一个remote => true,以及一个error.js.erb文件,确定如果不必重新加载页面,文件字段将保持不变。不幸的是,情况并非如此,因为我读到浏览器出于安全原因无法通过AJAX处理多部分表单/文件。然而,我随后发现了Remotipart宝石解决了这个问题。所以我的应用程序的相关部分如下所示......

_form.html.erb

_form.html.erb

<%= form_for(@article, :html => { :multipart => true }, :remote => TRUE) do |f| %>
  <div id="errors"></div>
  <%= f.text_field :title %>
  <%= f.text_area :body %>
  <%= f.file_field(:photo) %>
  <%= f.submit %>
<% end %>

articles_controller.rb (Create action)

articles_controller.rb(创建动作)

  def create
    @article = Article.new(params[:article])

    respond_to do |format|
      if @article.save
        format.html { redirect_to(@article, :notice => 'Article was successfully created.') }
        format.xml  { render :xml => @article, :status => :created, :location => @article }
      else
        format.html { render :action => "new" }
        format.xml  { render :xml => @article.errors, :status => :unprocessable_entity }
        format.js { render 'errors', :locals => { :item => @article } }
      end
    end
  end

errors.js.erb

errors.js.erb

<%= remotipart_response do %>
    $("#errors").empty().append('<div id="error_explanation"><h2><%= pluralize(item.errors.count, "error") %> prohibited this article from being saved:</h2><ul></ul></div>');
    <% item.errors.full_messages.each do |msg| %>
        $("#error_explanation ul").append("<li><%= escape_javascript(msg) %></li>");
    <% end %>
<% end %>

So basically, if there are validation errors, the js file adds those errors to the errors div on the form. In addition, the file field persists if filled in. It all works: it DOES create the content in the database and upload the file, OR throw up the errors without losing the file field if something fails validation, but one problem remains.

所以基本上,如果存在验证错误,js文件会将这些错误添加到表单上的errors div中。此外,如果填写,文件字段仍然存在。一切正常:它在数据库中创建内容并上传文件,如果某些内容验证失败,则抛出错误而不丢失文件字段,但仍存在一个问题。

When the form is submitted with a file uploaded, I get a 406 not permitted error in my log without a redirect to the show page. If the form does NOT have a file uploaded, then the log returns a 200 OK, but the page also is not redirected to the show action.

当提交表单并上传文件时,如果没有重定向到显示页面,我会在日志中收到406不允许的错误。如果表单没有上传文件,则日志返回200 OK,但页面也不会重定向到show动作。

After hunting on Google and other SO threads, I found this bit of code that supposedly would pass it the correct headers (and yes, jQuery is installed and runs before application.js)...

在Google和其他SO线程上搜索之后,我发现这段代码可能会传递给它正确的标题(是的,jQuery已安装并在application.js之前运行)...

application.js

的application.js

jQuery.ajaxSetup({ 
  'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})

...unfortunately it doesn't work. I'm out of ideas, any suggestions on how to beat that 406 issue and make this properly redirect?

......不幸的是它不起作用。我没有想法,有关如何击败406问题并使其正确重定向的任何建议?

2 个解决方案

#1


0  

I think that you are making this too complex, why not focus on preventing the users from uploading the file again after an error in the first place. The users continue on their merry way and you don't have to mess with ugly JavaScript hacks.

我认为你使这个过于复杂,为什么不专注于阻止用户在首次出错后再次上传文件。用户继续他们的快乐方式,你不必乱用丑陋的JavaScript黑客。

Store the file and redirect the user to an the create page with the file field filled in.

存储文件并将用户重定向到填写了文件字段的创建页面。

#2


0  

Haven't been able to come back to this issue until now, but I finally solved this. First off, I dropped the application.js code. Second, the 406 redirect was solved by including a format.js in the respond_to's save success...

直到现在还没有回到这个问题,但我终于解决了这个问题。首先,我删除了application.js代码。其次,通过在respond_to的保存成功中包含format.js来解决406重定向...

respond_to do |format|
  if @article.save
    format.js
    format.html { [...] }
  else
    [...]
  end
end

Only issue is, the page would not redirect at all, even if a redirect_to was placed in the format.js. It did trigger a create.js.erb file, so inside of that, I put...

唯一的问题是,即使redirect_to放在format.js中,页面根本不会重定向。它确实触发了一个create.js.erb文件,所以在其中,我把...

window.location.replace("/articles");

...to initiate the redirect upon loading create.js.erb. I would rather it respond and redirect via the controller rather than a javascript redirect, but I have yet to see a working solution to this issue (anything else I researched involving request.xhr code didn't work at all). But this works.

...在加载create.js.erb时启动重定向。我宁愿它通过控制器响应和重定向,而不是javascript重定向,但我还没有看到这个问题的工作解决方案(我研究涉及request.xhr代码的任何其他东西根本不起作用)。但这很有效。

However, a side benefit to doing it this way is that I can get more creative with the article saving, such as previewing the 'show' page for a few seconds before redirecting to the articles index, etc.

但是,这样做的另一个好处是,我可以通过保存文章获得更多创意,例如在重定向到文章索引之前预览“显示”页面几秒钟等。

#1


0  

I think that you are making this too complex, why not focus on preventing the users from uploading the file again after an error in the first place. The users continue on their merry way and you don't have to mess with ugly JavaScript hacks.

我认为你使这个过于复杂,为什么不专注于阻止用户在首次出错后再次上传文件。用户继续他们的快乐方式,你不必乱用丑陋的JavaScript黑客。

Store the file and redirect the user to an the create page with the file field filled in.

存储文件并将用户重定向到填写了文件字段的创建页面。

#2


0  

Haven't been able to come back to this issue until now, but I finally solved this. First off, I dropped the application.js code. Second, the 406 redirect was solved by including a format.js in the respond_to's save success...

直到现在还没有回到这个问题,但我终于解决了这个问题。首先,我删除了application.js代码。其次,通过在respond_to的保存成功中包含format.js来解决406重定向...

respond_to do |format|
  if @article.save
    format.js
    format.html { [...] }
  else
    [...]
  end
end

Only issue is, the page would not redirect at all, even if a redirect_to was placed in the format.js. It did trigger a create.js.erb file, so inside of that, I put...

唯一的问题是,即使redirect_to放在format.js中,页面根本不会重定向。它确实触发了一个create.js.erb文件,所以在其中,我把...

window.location.replace("/articles");

...to initiate the redirect upon loading create.js.erb. I would rather it respond and redirect via the controller rather than a javascript redirect, but I have yet to see a working solution to this issue (anything else I researched involving request.xhr code didn't work at all). But this works.

...在加载create.js.erb时启动重定向。我宁愿它通过控制器响应和重定向,而不是javascript重定向,但我还没有看到这个问题的工作解决方案(我研究涉及request.xhr代码的任何其他东西根本不起作用)。但这很有效。

However, a side benefit to doing it this way is that I can get more creative with the article saving, such as previewing the 'show' page for a few seconds before redirecting to the articles index, etc.

但是,这样做的另一个好处是,我可以通过保存文章获得更多创意,例如在重定向到文章索引之前预览“显示”页面几秒钟等。