Skip to content

how to add upload file feature from the cozy tutorial project

rdubigny edited this page Jul 18, 2013 · 18 revisions

Front-end

We need to replace the old create form by a html input file object. From client/app/views/templates/home.jade, replace the lines :

form#create-bookmark(action="#")
    input.title-field(placeholder="title")
    input.url-field(placeholder="url")
    button.btn.create-button create

by these ones :

input#uploader(type="file")

Now we need to connect it to our view. Kick the onCreateClicked function and his attached event from client/app/views/app_view.coffee. Instead, declare a new event handler as follow :

events:
    'change #uploader' : 'addFile'

addFile: ()=>
    attach = @uploader.files[0]
    fileAttributes = {}
    fileAttributes.title = attach.name
    bookmark = new Bookmark fileAttributes
    bookmark.file = attach
    @collection.add bookmark
    @upload track

# create a FormData object
# save the model
upload: (bookmark) =>
    formdata = new FormData()
    formdata.append 'cid', bookmark.cid
    formdata.append 'title', bookmark.get 'title'
    formdata.append 'file', bookmark.file
    # need to call sync directly so we can change the data
    Backbone.sync 'create', bookmark,
        contentType:false # Prevent $.ajax from being smart
        data: formdata

Note that we use a uploader attribute. We need to bind the uploader html object to a javascript object. In afterRenderfunction in client/app/views/app_view.coffee add the following line :

@uploader = @$('#uploader')[0]

Back-end

First we need to modify our model field description to prepare it to receive file. Modify the Bookmark declaration in db/schema.coffee as follow

Bookmark = define 'Bookmark', ->
    property 'title', String
    property 'slug', String
    property '_attachments', Object

To finish we just have to modify the create action in app/controllers/bookmarks_controller.coffee

action 'create', ->
    file = req.files["file"]
    req.body.slug = file.name

    Bookmark.create req.body, (err, newbookmark) =>
        if err
            send error: true, msg: "Server error while creating bookmark.", 500
        else
            newbookmark.attachFile file.path, {"name": file.name}, (err) ->
                if err
                    send error: true, msg: "Server error while add attachment file.", 500
                else
                    send newbookmark, 200

It's as simple as that.

Going a little further

Now if you simply want to access the uploaded files from your browser you can do something like that.

First create the html link in your template. Modify client/app/views/templates/bookmark.jade

a(href="bookmarks/#{model.id}/attach/#{model.title}", target="_blank") #{model.title}
button.delete-button Delete

Then signal this new path to the back-end router. In config/routes.coffee

map.get 'bookmarks/:id/attach/:title', 'bookmarks#getAttachment'

Eventually, add the corresponding action to app/controllers/bookmarks_controller.coffee

action 'getAttachment', ->
    title = params.title

    @bookmark.getFile title, (err, resp, body) ->
        if err or not resp?
            send 500
        else if resp.statusCode is 404
            send 'File not found', 404
        else if resp.statusCode != 200
            send 500
        else
            send 200
    .pipe(res) # this is compound "magic" res = response variable