Rails Valums Ajax 上传

Posted

技术标签:

【中文标题】Rails Valums Ajax 上传【英文标题】:Rails Valums Ajax Upload 【发布时间】:2013-02-21 15:56:45 【问题描述】:

我正在尝试让 Valums 上传器与我的 Rails 项目一起工作,但遇到了很多困难。

我目前有一个非常简单的使用 Paperclip 上传过程,使用标准模型和视图... 型号

class User
  include Mongoid::Document
  include Mongoid::Paperclip

  has_mongoid_attached_file :image

控制器

  def avatar
    @user = current_user
    respond_to do |format|
      format.html
    end
  end
  #working on the updateimage method
    def update
      file = params[:qqfile].is_a?(ActionDispatch::Http::UploadedFile) ? params[:qqfile] : params[:file]
        @user = current_user
        if @user.update_attributes(params[:user])
            render :text => '"success": true', :content_type => "application/json"
       else
            render :text => @user.errors.to_json, :content_type => "application/json"
       end
     end

查看

= form_for(@user, :as => @user, :url => '/updateimage', :html =>  :method => :post, :multipart => true ) do |f|
    #file-uploader
    =@user.firstname
    %img:src => current_user.image
    = f.file_field :image
    = f.submit

Soooooo... 这一切都有效,但是当我尝试使用 Valums jQuery 时:

  $('#file-uploader').fineUploader(
    debug: true,
    autoSubmit: true,
    allowedExtensions: ['jpg', 'jpeg', 'png', 'gif'],
    sizeLimit: 1048576, // max size: 1MB
    minSizeLimit: 0, // min size
    multiple: false,
    request: 
        endpoint: '/updateimage',
        paramsInBody: true
        
    );

我明白了:

undefined method `update_attributes' for nil:NilClass

我很乐意让它工作,但我对一般编程有点陌生,所以它对我来说仍然是一件相当抽象的事情。我很乐意提供额外的日志信息,请告诉我在哪里可以找到它。

路线

             admin_index GET    /admin(.:format)                       admin#index
                         POST   /admin(.:format)                       admin#create
               new_admin GET    /admin/new(.:format)                   admin#new
              edit_admin GET    /admin/:id/edit(.:format)              admin#edit
                   admin GET    /admin/:id(.:format)                   admin#show
                         PUT    /admin/:id(.:format)                   admin#update
                         DELETE /admin/:id(.:format)                   admin#destroy
                  orders GET    /orders(.:format)                      orders#index
                         POST   /orders(.:format)                      orders#create
               new_order GET    /orders/new(.:format)                  orders#new
              edit_order GET    /orders/:id/edit(.:format)             orders#edit
                   order GET    /orders/:id(.:format)                  orders#show
                         PUT    /orders/:id(.:format)                  orders#update
                         DELETE /orders/:id(.:format)                  orders#destroy
                 entries GET    /entries(.:format)                     entries#index
                         POST   /entries(.:format)                     entries#create
               new_entry GET    /entries/new(.:format)                 entries#new
              edit_entry GET    /entries/:id/edit(.:format)            entries#edit
                   entry GET    /entries/:id(.:format)                 entries#show
                         PUT    /entries/:id(.:format)                 entries#update
                         DELETE /entries/:id(.:format)                 entries#destroy
              home_index GET    /home(.:format)                        home#index
                         POST   /home(.:format)                        home#create
                new_home GET    /home/new(.:format)                    home#new
               edit_home GET    /home/:id/edit(.:format)               home#edit
                    home GET    /home/:id(.:format)                    home#show
                         PUT    /home/:id(.:format)                    home#update
                         DELETE /home/:id(.:format)                    home#destroy
                  avatar        /avatar(.:format)                      home#avatar
             updateimage POST   /updateimage(.:format)                 home#update
                    root        /                                      home#home
                    root        /                                      home#index
        new_user_session GET    /users/sign_in(.:format)               devise/sessions#new
            user_session POST   /users/sign_in(.:format)               devise/sessions#create
    destroy_user_session DELETE /users/sign_out(.:format)              devise/sessions#destroy
 user_omniauth_authorize        /users/auth/:provider(.:format)        users/omniauth_callbacks#passthru :provider=>/facebook/
  user_omniauth_callback        /users/auth/:action/callback(.:format) users/omniauth_callbacks#(?-mix:facebook)
           user_password POST   /users/password(.:format)              devise/passwords#create
       new_user_password GET    /users/password/new(.:format)          devise/passwords#new
      edit_user_password GET    /users/password/edit(.:format)         devise/passwords#edit
                         PUT    /users/password(.:format)              devise/passwords#update
cancel_user_registration GET    /users/cancel(.:format)                users/registrations#cancel
       user_registration POST   /users(.:format)                       users/registrations#create
   new_user_registration GET    /users/sign_up(.:format)               users/registrations#new
  edit_user_registration GET    /users/edit(.:format)                  users/registrations#edit
                         PUT    /users(.:format)                       users/registrations#update
                         DELETE /users(.:format)                       users/registrations#destroy
       user_confirmation POST   /users/confirmation(.:format)          devise/confirmations#create
   new_user_confirmation GET    /users/confirmation/new(.:format)      devise/confirmations#new
                         GET    /users/confirmation(.:format)          devise/confirmations#show
                    user GET    /users/:id(.:format)                   users#show

【问题讨论】:

显示rake routes 命令的输出。 已发布路线。 注意:当我的端点是“用户”时,它几乎是正确的。意思是,我在控制台中得到了回报,但我实际上并没有更新任何信息……不知道为什么。目前“用户”用于更新用户配置文件中的所有字段,而不仅仅是用户头像... 注意:也可以使用 Rack::RawUpload gem。 【参考方案1】:

该错误意味着您没有在响应中返回有效的 JSON。请参阅项目的server-side readme 了解更多信息。另一种可能是你的端点地址不正确。

【讨论】:

如何调试端点地址?端点与控制器功能不一样吗? '家/头像'? 我不是 Rails 人,所以我无法帮助你。只有您可以确定端点的地址是什么。我将从查看 HTTP 请求/响应开始。 Ray,感谢您的反馈,但如果您不能提供 Rails 特定的答案,我无法接受。我可以通过快速的 Google 搜索轻松找到您提供的内容。 我理解凯文,但是解决你问题的方法真的很简单。您没有指定正确的端点地址,或者您指定了正确的端点地址,但您的服务器端代码未返回有效的 JSON。您如何确定您的代码是否返回了有效的 JSON?查看原始响应并使用jsonlint。如果您的端点是错误的,那么没有人可以帮助您。您需要找出服务器的正确地址。此外,您的响应内容类型应该是 text/plain,而不是 application/json。这在自述文件中有详细说明。 谢谢,雷。也许问题可能出在我的路线文件中(我知道你不是 Rails 人)......如果你有时间,我是 Rails/编程的新手,你能告诉我为什么响应应该是文本而不是json?【参考方案2】:

如果您发布了您的全部路线,那么您错过了端点路线。例如:

put "/avatar" => "your_controller#update"

ps:在客户端或服务器端(放置或发布)调整http动词

您的update JSON 输出应该看起来像(根据 valums 项目 wiki):

if @photo.save
  render json: :success => true, :src => @photo.image.url(:thumb)
else
  render json: @photo.errors.to_json
end

【讨论】:

能给我一个更合适的控制器方法吗?我正在使用carrierwave和mongodb...【参考方案3】:

更新:我认为值得尝试不理会users#update 并创建一个单独的文件上传操作。

至于路由,FineUploader 仅执行 POST 请求,因此您必须添加新路由,因为 POST 请求到 /users 端点会触发 users#create 操作,这不是您想要的。

match '/avatar', :to => 'users#avatar', :via => :post

此外,您必须在服务器端处理文件上传。 This wiki page 描述了两种方法。例如,您可以使用rack-raw-upload gem 并将控制器代码更改为以下内容:

def update
  # this action does not handle AJAX file upload
  # ...
end

def avatar
  file = params[:qqfile].is_a?(ActionDispatch::Http::UploadedFile) ? params[:qqfile] : params[:file]
  @user = current_user
  if @user.update_attributes( :image => file )
    render :json =>  :success => true 
  else
    render :json =>  :success => false 
  end
end

注意config/application.rb 中必须有一行(如果您使用rack-raw-upload gem):

config.middleware.use 'Rack::RawUpload'

另外,看来paramsInBody应该属于request参数:

$('#file-uploader').fineUploader(
    request: 
        endpoint: "/avatar",
        paramsInBody: true
    ,
    debug: true
)

最后一点: 发出 AJAX 请求时,CSRF 令牌必须包含在标头中,以启用用户身份验证。可以通过编辑fineuploader.js 中的setHeaders 函数来完成——在该函数中添加以下行:

xhr.setRequestHeader("X-CSRF-Token", $("meta[name='csrf-token']").attr("content"));

【讨论】:

我觉得这更接近了......但我仍然收到错误 - 提交时用户已注销...... 我正在尝试一些不同的东西,但我得到了诸如“未定义方法'update_attributes'”之类的东西......我不知道该去哪里。如果你能引导我完成,我会尽我所能。 @KevinBrown 用户注销时模型字段会发生什么?它们的值是否正确更新? 不这么认为。我做了更多的傻事,现在我得到了Called id for nil, which would mistakenly be 4 -- if you really wanted the id of nil, use object_id 我有机会进一步检查。你能帮我吗?您的代码有效(没有 AJAX/VALUMS)并且没有 .merge。我正在使用 mongo——这会改变事情吗?为什么此功能适用于常规表单提交而不适用于值?!我没有正确配置 rawupload 吗?

以上是关于Rails Valums Ajax 上传的主要内容,如果未能解决你的问题,请参考以下文章

使用 Valums 在 Chrome 中上传大文件失败

大文件上的 JQuery Ajax 文件上传失败

Rails 4:如何使用 AJAX 上传文件

上传文件到服务器并发送邮件

Ruby on Rails AJAX文件上传

使用 Remotipart 的 Rails AJAX 上传表单