<commit_before>h1. S3SwfUpload Gem For Rails 3

S3SwfUpload allows user to upload a file to S3 directly, so you can save the cost of uploading process in your app server.

The flex application in this fork was completely re-written so that there are no flash or flex UI components.  The one exception to that is the browse button, which, for security purposes MUST be flash. But even then, you get to pass the URLs for images to use for that button!

The goal of this re-write is to put the power to customize this powerful took back in the hands of non-flex-savvy developers.  The look and feel is controlled by CSS, and any behavior is controlled by JavaScript.  Flex only handles the file management portion.  A nice result of this is that the flash file is only 46 kb, down from 288 kb.  If you see any way that this can be done better, please don't hesitate to let me know!

h2. Example

!http://static.nathancolgate.com/images/s3_swf_uploader_screenshot.png!

Watch a video of an example app being built using the gem on "Vimeo":http://vimeo.com/11363680

There is also a demo app running on heroku at "http://s3swfuploader.heroku.com/":http://s3swfuploader.heroku.com/

h2. Usage

1. Edit <code>Gemfile</code> and add this as a gem, you'll also need aws-s3

<pre><code>gem 's3_swf_upload', :git => 'git://github.com/nathancolgate/s3-swf-upload-plugin'
gem 'aws-s3', :require => 'aws/s3'
</code></pre>
	
2. Bundle it!

<pre><code>$ bundle install
</code></pre>

3. Run the generator

<pre><code>$ rails generate s3_swf_upload:uploader
</code></pre>
	
4. Configure your amazon parameters via the generated <code>config/amazon_s3.yml</code> file.

5. Generate the bucket (if you haven't already)

<pre><code>$ rake s3_swf_upload:make_bucket
</code></pre>
	
6. Upload the crossdomain.xml file (if you haven't already)

<pre><code>$ rake s3_swf_upload:make_crossdomain
</code></pre>

7. Note: you no longer need to edit <code>app/controller/s3_uploads_controller.rb</code>

In my tests in Rails 3, the application was able to correctly handle the requests from the flash object.

This means that your authentication systems can still be used to protect the signature generation.

8. Initialize the SWF object in your view using this handy helper:

<pre><code><%=raw s3_swf_upload_tag %>
</code></pre>

9. To achieve basic functionality, the only other thing you need is something to call the <code>startUploading</code> function.  For example:

<pre><code><input type="submit" value="Start Uploading" onclick="s3_swf_1_object.startUploading();" />
</code></pre>

However, you will have no feedback or interface to let you know that anything is actually happening.

10. If you want to customise its behavior, "here's a more complex example":http://gist.github.com/382979 

And the "CSS":http://gist.github.com/383118 to go along.

h2. File Renaming

In my applications I upload all files to _tmp_ folder and then have rails manipulate the file (renaming, resizing, etc). Here's a starting point to give you an idea of what that looks like using Paperclip: 

"How to integrate with Paperclip":http://gist.github.com/575842

I prefer this solution because it allows the application to keep tabs on the files. However, if you are looking for a pure javascript solution, check out some of the forks of this project.

h2. General Parameters

h3. :buttonWidth _(integer = 100)_

h3. :buttonHeight _(integer = 30)_

h3. :flashVersion _(string = '9.0.0')_

h3. :queueSizeLimit _(integer = 100)_

Maximum number of files that can be added to the queue.

h3. :fileSizeLimit _(integer = 524288000)_

Individual file size limit in bytes (default is 512 MB)

h3. :fileTypes _(string = '*.*')_

Something like this also works: <code>'*.jpg;*.gif;*.png;'</code>

h3. :fileTypeDescs _(string = 'All Files')_

Something like this also works: <code>'Image files.'</code>

h3. :selectMultipleFiles _(boolean = true)_

Set this to false if you only want to allow users to pick one file at a time.

h3. :keyPrefix _(string = '')_

String to be prepended to the uploaded file name to make the Amazon S3 key (location in bucket).

h3. :signaturePath _(string = '/s3_uploads.xml')_

Fully qualified path to the controller and action that will serve up the Amazon S3 signature

h3. :buttonUpPath _(string = '/flash/s3_up_button.gif')_

Fully qualified path to an image to be used as the Browse Button (in the up state).  Image should have same dimensions as the buttonWidth and buttonHeight parameters.

h3. :buttonOverPath _(string = '/flash/s3_over_button.gif')_

Fully qualified path to an image to be used as the Browse Button (in the over state).  Image should have same dimensions as the buttonWidth and buttonHeight parameters.

h3. :buttonDownPath _(string = '/flash/s3_down_button.gif')_

Fully qualified path to an image to be used as the Browse Button (in the down state).  Image should have same dimensions as the buttonWidth and buttonHeight parameters.

h2. Callback Parameters

The real power of this refactoring is that the flex application makes all of the following calls to JavaScript.  What you do with the calls is totally up to you:

* :onFileAdd _(file)_
* :onFileRemove _(file)_
* :onFileSizeLimitReached _(file)_
* :onFileNotInQueue _(file)_
* :onQueueChange _(queue)_
* :onQueueSizeLimitReached _(queue)_
* :onQueueEmpty _(queue)_
* :onQueueClear _(queue)_
* :onUploadingStart _()_
* :onUploadingStop _()_
* :onUploadingFinish _()_
* :onSignatureOpen _(file,event)_
* :onSignatureProgress _(file,progress_event)_
* :onSignatureSecurityError _(file,security_error_event)_
* :onSignatureComplete _(file,event)_
* :onSignatureIOError _(file,io_error_event)_
* :onSignatureHttpStatus _(file,http_status_event)_
* :onSignatureXMLError _(file,error_message)_
* :onUploadError _(upload_options,error)_
* :onUploadOpen _(upload_options,event)_
* :onUploadProgress _(upload_options,progress_event)_
* :onUploadIOError _(upload_options,io_error_event)_
* :onUploadHttpStatus _(upload_options,http_status_event)_
* :onUploadSecurityError _(upload_options,security_error_event)_
* :onUploadComplete _(upload_options,event)_

h2. JavaScript Functions

The following functions can be called on the generated object.  Normally the call looks something like this:

<pre><code>s3_swf_1_object.startUploading();
</code></pre>

h3. startUploading

Starts the uploading process

h3. stopUploading

Stops the uploading process.  Note: Stopping and restarting the uploading process is buggy.  I'd avoid it.

h3. clearQueue

Clears all files out of the queue.

h3. removeFileFromQueue(integer)

Removes a specific file from the queue.

h2. Will it work with < Rails 3?

You bet.  The Rails 3 specific gem only makes installation and setup easier.  Download the gem to your desktop (or similar non-gem path location) and perform all the Usage steps by hand.  Namely: 

 * copy the "template files":http://github.com/nathancolgate/s3-swf-upload-plugin/tree/master/lib/s3_swf_upload/railties/generators/uploader/templates/ into your application (use the "generator":http://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb as a road map)
* copy the "view helpers":http://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/view_helpers.rb into your applications <code>/lib</code> directory.

You'll want to add the view helper to an initialization file: <code>require 'view_helpers'</code>

h2. Known Issues

1. As much as I would like the interface to be 100% HTML, a (legitimate) security feature in Flash does not allow it:

bq. "With Adobe Flash Player 10, the <code>FileReference.browse</code> and <code>FileReference.download</code>  operations may be initiated only through ActionScript that originates from user interaction." - "Adobe TechNote":http://kb2.adobe.com/cps/405/kb405546.html

The next best thing I could come up with was to pass images in as buttons.

-If the <code>startUploading</code> call is made after calling <code>stopUploading</code>, only the first file in the queue is successfully uploaded.-

h2. Kudos

Original plugin is Copyright (c) 2008 elctech, released under the MIT license

Updates to plugin for multiple file uploader are Copyright (c) 2010 PRX, released under the MIT license

Conversion of plugin to gem for rails 3 is Copyright (c) 2010 <NAME>, released under the MIT license<commit_msg>updating readme doc with more tips for pre rails 3<commit_after>h1. S3SwfUpload Gem For Rails 3

S3SwfUpload allows user to upload a file to S3 directly, so you can save the cost of uploading process in your app server.

The flex application in this fork was completely re-written so that there are no flash or flex UI components.  The one exception to that is the browse button, which, for security purposes MUST be flash. But even then, you get to pass the URLs for images to use for that button!

The goal of this re-write is to put the power to customize this powerful took back in the hands of non-flex-savvy developers.  The look and feel is controlled by CSS, and any behavior is controlled by JavaScript.  Flex only handles the file management portion.  A nice result of this is that the flash file is only 46 kb, down from 288 kb.  If you see any way that this can be done better, please don't hesitate to let me know!

h2. Example

!http://static.nathancolgate.com/images/s3_swf_uploader_screenshot.png!

Watch a video of an example app being built using the gem on "Vimeo":http://vimeo.com/11363680

There is also a demo app running on heroku at "http://s3swfuploader.heroku.com/":http://s3swfuploader.heroku.com/

h2. Usage

1. Edit <code>Gemfile</code> and add this as a gem, you'll also need aws-s3

<pre><code>gem 's3_swf_upload', :git => 'git://github.com/nathancolgate/s3-swf-upload-plugin'
gem 'aws-s3', :require => 'aws/s3'
</code></pre>
	
2. Bundle it!

<pre><code>$ bundle install
</code></pre>

3. Run the generator

<pre><code>$ rails generate s3_swf_upload:uploader
</code></pre>
	
4. Configure your amazon parameters via the generated <code>config/amazon_s3.yml</code> file.

5. Generate the bucket (if you haven't already)

<pre><code>$ rake s3_swf_upload:make_bucket
</code></pre>
	
6. Upload the crossdomain.xml file (if you haven't already)

<pre><code>$ rake s3_swf_upload:make_crossdomain
</code></pre>

7. Note: you no longer need to edit <code>app/controller/s3_uploads_controller.rb</code>

In my tests in Rails 3, the application was able to correctly handle the requests from the flash object.

This means that your authentication systems can still be used to protect the signature generation.

8. Initialize the SWF object in your view using this handy helper:

<pre><code><%=raw s3_swf_upload_tag %>
</code></pre>

9. To achieve basic functionality, the only other thing you need is something to call the <code>startUploading</code> function.  For example:

<pre><code><input type="submit" value="Start Uploading" onclick="s3_swf_1_object.startUploading();" />
</code></pre>

However, you will have no feedback or interface to let you know that anything is actually happening.

10. If you want to customise its behavior, "here's a more complex example":http://gist.github.com/382979 

And the "CSS":http://gist.github.com/383118 to go along.

h2. File Renaming

In my applications I upload all files to _tmp_ folder and then have rails manipulate the file (renaming, resizing, etc). Here's a starting point to give you an idea of what that looks like using Paperclip: 

"How to integrate with Paperclip":http://gist.github.com/575842

I prefer this solution because it allows the application to keep tabs on the files. However, if you are looking for a pure javascript solution, check out some of the forks of this project.

h2. General Parameters

h3. :buttonWidth _(integer = 100)_

h3. :buttonHeight _(integer = 30)_

h3. :flashVersion _(string = '9.0.0')_

h3. :queueSizeLimit _(integer = 100)_

Maximum number of files that can be added to the queue.

h3. :fileSizeLimit _(integer = 524288000)_

Individual file size limit in bytes (default is 512 MB)

h3. :fileTypes _(string = '*.*')_

Something like this also works: <code>'*.jpg;*.gif;*.png;'</code>

h3. :fileTypeDescs _(string = 'All Files')_

Something like this also works: <code>'Image files.'</code>

h3. :selectMultipleFiles _(boolean = true)_

Set this to false if you only want to allow users to pick one file at a time.

h3. :keyPrefix _(string = '')_

String to be prepended to the uploaded file name to make the Amazon S3 key (location in bucket).

h3. :signaturePath _(string = '/s3_uploads.xml')_

Fully qualified path to the controller and action that will serve up the Amazon S3 signature

h3. :buttonUpPath _(string = '/flash/s3_up_button.gif')_

Fully qualified path to an image to be used as the Browse Button (in the up state).  Image should have same dimensions as the buttonWidth and buttonHeight parameters.

h3. :buttonOverPath _(string = '/flash/s3_over_button.gif')_

Fully qualified path to an image to be used as the Browse Button (in the over state).  Image should have same dimensions as the buttonWidth and buttonHeight parameters.

h3. :buttonDownPath _(string = '/flash/s3_down_button.gif')_

Fully qualified path to an image to be used as the Browse Button (in the down state).  Image should have same dimensions as the buttonWidth and buttonHeight parameters.

h2. Callback Parameters

The real power of this refactoring is that the flex application makes all of the following calls to JavaScript.  What you do with the calls is totally up to you:

* :onFileAdd _(file)_
* :onFileRemove _(file)_
* :onFileSizeLimitReached _(file)_
* :onFileNotInQueue _(file)_
* :onQueueChange _(queue)_
* :onQueueSizeLimitReached _(queue)_
* :onQueueEmpty _(queue)_
* :onQueueClear _(queue)_
* :onUploadingStart _()_
* :onUploadingStop _()_
* :onUploadingFinish _()_
* :onSignatureOpen _(file,event)_
* :onSignatureProgress _(file,progress_event)_
* :onSignatureSecurityError _(file,security_error_event)_
* :onSignatureComplete _(file,event)_
* :onSignatureIOError _(file,io_error_event)_
* :onSignatureHttpStatus _(file,http_status_event)_
* :onSignatureXMLError _(file,error_message)_
* :onUploadError _(upload_options,error)_
* :onUploadOpen _(upload_options,event)_
* :onUploadProgress _(upload_options,progress_event)_
* :onUploadIOError _(upload_options,io_error_event)_
* :onUploadHttpStatus _(upload_options,http_status_event)_
* :onUploadSecurityError _(upload_options,security_error_event)_
* :onUploadComplete _(upload_options,event)_

h2. JavaScript Functions

The following functions can be called on the generated object.  Normally the call looks something like this:

<pre><code>s3_swf_1_object.startUploading();
</code></pre>

h3. startUploading

Starts the uploading process

h3. stopUploading

Stops the uploading process.  Note: Stopping and restarting the uploading process is buggy.  I'd avoid it.

h3. clearQueue

Clears all files out of the queue.

h3. removeFileFromQueue(integer)

Removes a specific file from the queue.

h2. Will it work with < Rails 3?

You bet.  The Rails 3 specific gem only makes installation and setup easier. Here are some tips for getting this to work with < Rails 3:

* install it as a plugin <code>script/plugin install git://github.com/nathancolgate/s3-swf-upload-plugin.git</code>
* copy the "template files":http://github.com/nathancolgate/s3-swf-upload-plugin/tree/master/lib/s3_swf_upload/railties/generators/uploader/templates/ into your application (use the "generator":http://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/railties/generators/uploader/uploader_generator.rb as a road map)
* copy the "view helpers":http://github.com/nathancolgate/s3-swf-upload-plugin/blob/master/lib/s3_swf_upload/view_helpers.rb into your applications <code>/lib</code> directory.
* add the view helper to an initialization file: <code>require 'view_helpers'</code>
* load the config file by adding this to the bottom of your environment.rb file: <code>S3SwfUpload::S3Config.load_config</code>
* replace references to Rails.root or Rails.env in the <code>/vendor/plugins/s3-swf-upload-plugin/lib/s3_swf_upload/s3_config.rb</code> file.
* comment out the require railties inside <code>/vendor/plugins/s3-swf-upload-plugin/lib/s3_swf_upload.rb</code>
* you may need to require 's3_swf_upload' and 'aws/s3' in your environment.rb file
* your route will be map.resources instead of resources.

h2. Known Issues

1. As much as I would like the interface to be 100% HTML, a (legitimate) security feature in Flash does not allow it:

bq. "With Adobe Flash Player 10, the <code>FileReference.browse</code> and <code>FileReference.download</code>  operations may be initiated only through ActionScript that originates from user interaction." - "Adobe TechNote":http://kb2.adobe.com/cps/405/kb405546.html

The next best thing I could come up with was to pass images in as buttons.

-If the <code>startUploading</code> call is made after calling <code>stopUploading</code>, only the first file in the queue is successfully uploaded.-

h2. Kudos

Original plugin is Copyright (c) 2008 elctech, released under the MIT license

Updates to plugin for multiple file uploader are Copyright (c) 2010 PRX, released under the MIT license

Conversion of plugin to gem for rails 3 is Copyright (c) 2010 <NAME>, released under the MIT license
{'fraction_non_alphanumeric': 0.08754807968310466, 'fraction_numerical': 0.018830013203972675, 'mean_word_length': 4.826086956521739, 'pattern_counts': {'":': 18, '<': 132, '<?xml version=': 0, '>': 133, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 4}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 3, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '566363', 'n_tokens_mistral': 5486, 'n_tokens_neox': 5223, 'n_words': 2135}