简体   繁体   English

Ruby on Rails:使用AJAXified表格找出406错误/缺少重定向

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

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. 我有一个带有“ Article”支架的项目-其中包括缩略图的回形针文件字段-团队中的其他人抱怨提交表单时必须如何再次将文件添加到字段中,并且验证错误是由于缺少另一个字段上的数据而触发。

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. 考虑到这是由于浏览器的限制所致,我在表单中添加了一个remote => true以及一个error.js.erb文件,从而确定了如果不必重新加载页面的情况下文件字段仍然存在。 Unfortunately that wasn't the case, as I read that browsers are unable to process multipart forms / files through AJAX for security reasons. 不幸的是,事实并非如此,因为我读到出于安全原因,浏览器无法通过AJAX处理多部分表单/文件。 However, I then discovered the Remotipart gem which solves this issue. 但是,我随后发现了Remotipart宝石 ,可以解决此问题。 So the relevant parts of my application looks like the following... 因此,应用程序的相关部分如下所示:

_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) article_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. 因此,基本上,如果存在验证错误,那么js文件会将这些错误添加到表单上的错误div上。 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. 此外,如果填写了文件字段,则该字段仍然存在。所有工作都可以:它确实在数据库中创建了内容并上传了文件,或者在某些验证失败的情况下抛出了错误而不会丢失文件字段,但是仍然存在一个问题。

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. 提交表单并上传文件时,我的日志中出现406不允许错误,而没有重定向到显示页面。 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. 如果表单没有上载文件,则日志将返回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问题并使其正确重定向的任何建议?

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. 存储文件,然后将用户重定向到填写了文件字段的创建页面。

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. 首先,我删除了application.js代码。 Second, the 406 redirect was solved by including a format.js in the respond_to's save success... 其次,通过在response_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. 唯一的问题是,即使将redirect_to放置在format.js中,页面也根本不会重定向。 It did trigger a create.js.erb file, so inside of that, I put... 它确实触发了一个create.js.erb文件,所以在其中,我放了...

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

...to initiate the redirect upon loading create.js.erb. ...以在加载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). 我希望它通过控制器进行响应和重定向,而不是通过JavaScript进行重定向,但是我还没有看到针对此问题的有效解决方案(我研究过的涉及request.xhr代码的所有其他方法都根本无效)。 But this works. 但这有效。

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. 但是,这样做的另一个好处是,我可以通过节省文章来提高创意,例如在重定向到文章索引之前预览“显示”页面几秒钟,等等。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM