0

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

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

_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(创建动作)

  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

错误.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 %>

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

当表单与上传的文件一起提交时,我的日志中出现 406 not allowed 错误,而没有重定向到显示页面。如果表单没有上传文件,则日志返回 200 OK,但页面也不会重定向到 show 操作。

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

应用程序.js

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

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

4

2 回答 2

0

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

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

于 2011-05-17T22:44:10.220 回答
0

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

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

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

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

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

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

于 2011-07-19T16:02:20.507 回答