我有一个带有“文章”脚手架的项目 - 其中包含缩略图的回形针文件字段 - 团队中的其他人抱怨他们在提交表单时需要再次将文件添加到字段中由于另一个字段上的数据丢失而触发了验证错误。
确定这是由于浏览器的限制,我添加了一个遥控器=>对于表单以及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
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 %>
基本上,如果存在验证错误,则js文件会将这些错误添加到表单上的errors div中。此外,如果填写,文件字段仍然存在。一切正常:它在数据库中创建内容并上传文件,如果某些内容验证失败,则抛出错误而不丢失文件字段,但仍存在一个问题。
当提交表单并上传文件时,如果没有重定向到显示页面,我会在日志中收到406不允许的错误。如果表单没有上传文件,则日志返回200 OK,但页面也不会重定向到show动作。
在谷歌和其他SO线程上搜索之后,我发现这段代码可能会传递给它正确的标题(是的,jQuery已经安装并在application.js之前运行)...
的application.js
jQuery.ajaxSetup({
'beforeSend': function(xhr) {xhr.setRequestHeader("Accept", "text/javascript")}
})
......遗憾的是它不起作用。我没有想法,有关如何击败406问题的任何建议并使其正确重定向?
答案 0 :(得分:0)
我认为你这太复杂了,为什么不专注于阻止用户在首次出错后再次上传文件。用户继续他们的快乐方式,你不必乱用丑陋的JavaScript黑客。
存储文件并将用户重定向到填写了文件字段的创建页面。
答案 1 :(得分: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代码的任何其他东西根本不起作用)。但这很有效。
然而,这样做的另一个好处是,我可以通过保存文章获得更多创意,例如在重定向到文章索引之前预览“显示”页面几秒钟等。