# HTML5 File uploader for rails

This gem use https://github.com/blueimp/jQuery-File-Upload for upload files.

## Install

In Gemfile:

```
gem 'rails-uploader'
```

In routes:

``` ruby
mount Uploader::Engine => '/uploader'
```

Migration for ActiveRecord:

```bash
$> rake uploader:install:migrations
```

## Usage

Architecture to store uploaded files (cancan integration):

``` ruby
class Asset < ActiveRecord::Base
  include Uploader::Asset
end

class Picture < Asset
  mount_uploader :data, PictureUploader, mount_on: :data_file_name
  validates :data, file_size: { maximum: 5.megabytes.to_i }

  def thumb_url
    url(:thumb)
  end
end
```

For example user has one picture:

``` ruby
class User < ActiveRecord::Base
  has_one :picture, as: :assetable, dependent: :destroy

  fileuploads :picture
end
```

Find asset by foreign key or guid:

``` ruby
@user.fileupload_asset(:picture)
```

### Include assets

Javascripts:

```
//= require uploader/application
```

Stylesheets:

```
*= require uploader/application
```

### Views

```erb
<%= uploader_field_tag :article, :photo %>
```

or FormBuilder:

```erb
<%= form.uploader_field :photo, sortable: true %>
```

### Formtastic

```erb
<%= f.input :pictures, as: :uploader %>
```

### SimpleForm

```erb
<%= f.input :pictures, as: :uploader, input_html: { sortable: true } %>
```

#### Confirming deletions

This is only working in Formtastic and FormBuilder:

``` erb
# formtastic
<%= f.input :picture, :as => :uploader, :confirm_delete => true %>
# the i18n lookup key would be en.formtastic.delete_confirmations.picture
```

## Authorization

Setup custom authorization adapter and current user:

``` ruby
# config/initializers/uploader.rb
Uploader.setup do |config|
  config.authorization_adapter = CanCanUploaderAdapter
  config.current_user_proc = -> (request) { request.env['warden'].user }
end
```

CanCanUploaderAdapter class just create cancan ability object and call can? method with same args:

``` ruby
class CanCanUploaderAdapter < Uploader::AuthorizationAdapter
  def authorized?(action, subject = nil)
    cancan_ability.can?(action, subject)
  end

  def scope_collection(collection, action = :index)
    collection.accessible_by(cancan_ability, action)
  end

  protected

  def cancan_ability
    @cancan_ability ||= Ability.new(user)
  end
end
```

## JSON Response

https://github.com/blueimp/jQuery-File-Upload/wiki/Setup#using-jquery-file-upload-ui-version-with-a-custom-server-side-upload-handler

Extend your custom server-side upload handler to return a JSON response akin to the following output:

``` json
{"files": [
  {
    "name": "picture1.jpg",
    "size": 902604,
    "url": "http:\/\/example.org\/files\/picture1.jpg",
    "thumb_url": "http:\/\/example.org\/files\/thumbnail\/picture1.jpg",
    "id": 1,
    "content_type": "image/jpg"
  },
  {
    "name": "picture2.jpg",
    "size": 841946,
    "url": "http:\/\/example.org\/files\/picture2.jpg",
    "thumb_url": "http:\/\/example.org\/files\/thumbnail\/picture2.jpg",
    "id": 2,
    "content_type": "image/jpg"
  }
]}
```

To return errors to the UI, just add an error property to the individual file objects:

``` json
{"files": [
  {
    "name": "picture1.jpg",
    "size": 902604,
    "error": "Filetype not allowed"
  },
  {
    "name": "picture2.jpg",
    "size": 841946,
    "error": "Filetype not allowed"
  }
]}
```

When removing files using the delete button, the response should be like this:

``` json
{"files": [
  {
    "picture1.jpg": true
  },
  {
    "picture2.jpg": true
  }
]}
```

Note that the response should always be a JSON object containing a files array even if only one file is uploaded.

### Customize JSON response and views

To customize JSON response just overwrite to_fileupload method:

``` ruby
class Asset
  include Uploader::Asset

  def to_fileupload
    {
      id: id,
      name: filename,
      content_type: content_type,
      size: size,
      url:  url,
      thumb_url: thumb_url
    }
  end
end
```

For exsample let's overwrite id method to public_token method:

``` ruby
class Asset
  include Uploader::Asset

  def to_fileupload
    super.merge(id: public_token)
  end

  def self.fileupload_find_asset(params)
    where(public_token: params[:id]).first
  end
end
```

To customize views just create new theme. For example create avatar theme:

    app/views/uploader/avatar/_container.html.erb
    app/views/uploader/avatar/_download.html.erb
    app/views/uploader/avatar/_upload.html.erb

And pass theme to input field:

``` slim
= form.uploader_field :photo, theme: 'avatar'
```

## Chunked file uploads

Chunked file uploads are only supported by browsers with support for XHR file uploads and the Blob API, which includes Google Chrome and Mozilla Firefox 4+.

To upload large files in smaller chunks, set the max_chunk_size option to a preferred maximum chunk size in Bytes:

``` slim
= f.uploader_field :video, data: { max_chunk_size: 10_000_000 }
```

That's it!

## Contributing

1. Fork it
2. Create your feature branch (`git checkout -b my-new-feature`)
3. Commit your changes (`git commit -am 'Added some feature'`)
4. Push to the branch (`git push origin my-new-feature`)
5. Create new Pull Request

## Testing

    rspec ./spec/

Copyright (c) 2016 Fodojo LLC, released under the MIT license