Kevin Brown
Kevin Brown

Reputation: 12650

Rails Valums Ajax Upload

I'm trying to get Valums uploader to work with my rails project and having a lot of difficulty.

I currently have a really simple upload process with Paperclip using the standard model and view... Model

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

  has_mongoid_attached_file :image

Controller

  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

View

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

Soooooo... this all works, but when I try to use 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
        }
    });

I get this:

undefined method `update_attributes' for nil:NilClass

I'd love to get this working, but I'm a little new to programming in general, so it's still quite an abstract thing for me. I'm happy to provide additional log info, just tell me where to find it.

Routes

             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

Upvotes: 3

Views: 543

Answers (3)

Ray Nicholus
Ray Nicholus

Reputation: 19890

That error means that you are not returning valid JSON in your response. Please see the poject's server-side readme for more information. Another possibility is that your endpoint address is incorrect.

Upvotes: -1

Ilia Khokhriakov
Ilia Khokhriakov

Reputation: 3687

Update: I think it's worth trying to leave users#update alone and create a separate action for file uploading.

As for the routes, FineUploader performs only POST requests so you have to add a new route because POST request to /users endpoint would trigger users#create action which is not what you want.

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

Furthermore, you have to handle file uploading on server side. This wiki page describes two methods. For instance, you can use rack-raw-upload gem and change controller code to the following:

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

Note that there has to be a line in config/application.rb (if you use rack-raw-upload gem):

config.middleware.use 'Rack::RawUpload'

Moreover, it seems that paramsInBody should belong to request parameter:

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

The final note: CSRF token must be included in headers when making AJAX request in order to enable user authentication. It can be done by editing setHeaders function in fineuploader.js — add the following line to this function:

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

Upvotes: 2

m4tm4t
m4tm4t

Reputation: 2381

If you have posted your entire routes, then you are missing the endpoint route. Eg:

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

ps: adapt the http verb on client or server side (put or post)

And your update JSON outputs should look like (according to valums project wiki):

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

Upvotes: 1

Related Questions