我在尝试使用bootsy gem上传文件时遇到了问题,但问题与bootsy本身无关。 Bootsy生成一个具有以下定义的表单:
<form class="bootsy-upload-form form-inline" id="new_image" data-type="json" enctype="multipart/form-data" action="/bootsy/image_galleries/67/images" accept-charset="UTF-8" data-remote="true" method="post">
<input name="utf8" value="✓" type="hidden">
<input name="authenticity_token" id="authenticity_token" value="1pQMR5j33OKupMg4TSnQafLQx1BxzWjkP1KqTfZafqDRfGqwB8r2J4FzRE+dyuoHVOw/W0qd1FZ1JoJsJFThDQ==" type="hidden">
...
当我尝试上传文件时,执行此行:
this.uploadInput.closest('form').submit();
我之前添加了警告,所以我会看到表单的序列化数据是如何显示的,所有字段都按预期显示(包括真实性标记等):
alert(this.uploadInput.closest('form').serialize());
提交表单时,在POST请求期间没有数据发送,只有标题,在浏览器检查器中看不到任何内容,在rails的日志文件中看不到任何内容,它只是这样:
Started POST "/bootsy/image_galleries/47/images" for ::1 at 2016-02-05 11:20:04 +0100
Processing by Bootsy::ImagesController#create as HTML
Parameters: {"image_gallery_id"=>"47"}
Can't verify CSRF token authenticity
Completed 422 Unprocessable Entity in 0ms (ActiveRecord: 0.0ms)
FATAL -- :
ActionController::InvalidAuthenticityToken - ActionController::InvalidAuthenticityToken:
_ actionpack (4.2.4) lib/action_controller/metal/request_forgery_protection.rb:181:in `handle_unverified_request'_
我在表单中生成了真实性令牌,我在元标记中有令牌,一切看起来都很好,没有任何错误被抛出。我还尝试创建类似于我的真实项目的示例应用程序,它按预期工作,形成正常提交的数据 - 当我尝试比较HTML代码和附加到两者的javascript事件时,它们几乎相似,因为其他因为其他部分宝石像ajax_pagination等,但没有任何部分,这应该导致这样的行为。
我正在使用Rails 4.2.4,使用body元素上的属性data-no-turbolink禁用turbolinks,项目使用bootstrap并包含JS库,如jQuery,下划线,欧芹,momentjs。
我会很感激任何想法,可能出现的问题,为什么表单不应该提交任何数据,哪里可能是一个问题。提前感谢任何提示。
更新 为了澄清事情,我在使用AJAX发送之前拍摄了一个状态图片 - 这个javascript是jQuery的jquery_ujs = RoR适配器的一部分。您可以看到,该数据包含发送前的所有表单域:
更新2: 只是一些信息,bootsy gem,负责创建表单使用remotipart将文件附加到请求。仍然......我正在调试javascript并且无法识别问题。这两个项目都有相同版本的jquery和remotipart,也是相同版本的rails。看起来这将是一个谜。
更新3: 所以我几乎解决了这个问题 - 上传现在正在运行,看起来这是javascript库的顺序问题。我会在确定问题后立即发布结果 - 我会撤消更改并尝试再次修复。
答案 0 :(得分:2)
问题在于application.js中包含的javascript库顺序。 Bootsy是在jquery-fileupload之后定义的。似乎Bootsy必须在它之前定义,通过这种设置,两者都运作良好。所以说:
//= require jquery-fileupload
//= require bootsy
//= require bootsy/locales/cs.js
之后(工作):
//= require bootsy
//= require bootsy/locales/cs.js
//= require jquery-fileupload
答案 1 :(得分:1)
似乎未按预期将真实性令牌发送到服务器。
我会查看浏览器中的“网络请求”标签,并检查帖子的正文。
我认为将processData设置为false是正确的。根据{{3}},
默认情况下,作为对象传入数据选项的数据(技术上,不是字符串)将被处理并转换为查询字符串
此外,您可以在检查令牌之前在控制器中添加它:
before_filter { puts params }
我会 不 在过滤前跳过真实性标记。
此外,在您的图像“但数据未发送到服务器:”,您正在查看标题。真实性令牌在身体中发送。
我认为问题在于表单的编码方式。你不应该编码它。将内容类型设置为multipart / form-data。内容类型目前设置为'application / x-www-form-urlencoded'。
服务器对表单进行URL解码,将所有字段合并为一个。这就是为什么它找不到真实性标记。
根据JQuery docs,您应该在ajax请求中将contentType设置为false。或者,您可以将其设置为multipart / form-data。
答案 2 :(得分:0)
默认情况下,表单只发送普通数据。如果您需要发送图像以及发布请求,您可以使用remotipart gem。它很棒。我自己用过它。
答案 3 :(得分:0)
我有两个理论,其中没有一个与你的形式无关:
第一理论:
随着您的问题更新,如果仔细观察,Cookie不会包含_csrf_token
。如果未传递_csrf_token
,则Rails将引发该错误消息。
我无法看到您的表单是否使用此值生成自己的隐藏字段。可能是你的一个项目这样做而另一个没有。你应该看看它。
如果这是问题,您可以找到各种解决方案。其中之一是在视图的HTML头中包含[csfr_meta_tag]
。请查看this以获取更多详细信息。
第二种理论:
如果您正在执行CORS请求,您的浏览器会首先发出一个额外的OPTIONS请求,以检查您是否有权访问此资源。
显然,_session_id
无法在CORS中发送,除非您启用它。为此,您需要处理OPTIONS请求。这是通过修改控制器Access-Control-Allow-Origin
和Access-Control-Allow-Methods
方法上的Access-Control-Allow-Headers
,before_filter
和after_filter
标头来完成的。
Here有一个要点,显示了一个例子(忘记skip_before_filter
行!)。如果您想获得指定标头值的更多详细信息,请检查this资源输出。
这些是我的理论,希望能帮到你!
<强>更新强>
如果你的两个项目都在使用Rails v4.2,那么可行的项目可能会设置protect_from_forgery
,如下所示:
protect_from_forgery
# OR maybe
protect_from_forgery with: :null_session
无效的那个已设置protect_from_forgery
,如下所示:
protect_from_forgery with: :exception
它们之间的区别在于发现未经验证的请求时的应用程序行为。查看更多here。
答案 4 :(得分:0)
在没有看到你的实际代码的情况下,我们会在猜测中并在黑暗中拍摄,但是看起来很明显,我认为你已经遵循了所有的宝石指令?安装生成器使用资产管道并设置初始化器等。这似乎相当明显,但你确定在应用程序中的模型上做白名单booty param是不行的吗? (根据https://github.com/volmer/bootsy)
private
def post_params
params.require(:post).permit(:title, :content, :bootsy_image_gallery_id)
end
答案 5 :(得分:-1)
CRSF身份验证问题是跨站点脚本问题。要解决此问题,请执行其中一项,
skip_before_action :verify_authenticity_token in your controller
或者您可以在应用程序控制器中对此行进行注释。
protect_from_forgery with: :exception