I just implemented a new way of uploading assets such as photos and PDF-files to Lokalebasen.dk. There is nothing revolutionary about it, but I hit a few snags on the way, and I thought I’d share my choices here.
Lokalebasen (a Danish website for rental and sale of business property) is (of course) based on Ruby on Rails and uses the notoriously brilliant jQuery as Javascript framework. When the customer asked for a progress bar while uploading assets, I knew there was basically two choices: Polling the server for the progress of the upload, or uploading through Flash. I choose the last option because I believe it is easier to implement, and it gives the added bonus of being able to start the upload in an “ajaxy” way without refreshing the page.
Several ready-made solutions exists, and chose one that was built as a jQuery plugin, was updated recently and was easy to use while being highly configurable: Uploadify. This article is not an Uploadify tutorial – you’ll have to work the out from the documentation and the examples. Rather, it’s about the last piece of the puzzle, how to make Rails play nicely with Uploadify.
Lokalebasen uses attachment_fu for handling assets. Since traditional file upload was already implemented, I had fallback functionality for users without Javascript or Flash – and so should you. All I had to add the controller handling the upload was a detection of the correct content type. Browsers will usually provide this, but Flash does not. And so the controller ended up looking something like this:
The mime-types gem is used to detect the content type – installation and usage is explained here.
I needed the functionality several places, so I wrote a partial I could reuse:
There is a lot going here, so let’s take it from the top. The content_for :head section is the code that will be placed inside the <head> part of the page – my layout takes care of that with a yield :head call. So first the Uploadify jQuery plugin javascript file is included, followed by some javascript that applies Uploadify to the file_uploader div seen later in the partial. This includes a lot options, some of which uses variables supplied to the partial. Here is an example of how I call the partial:
I won’t walk you through all the options I supply for Uploadify, but let’s take a look at the important ones: script is where Uploadify will post the uploaded file to. This should be the create action of your asset controller. scriptData is the most tricky one. The option specifies what parameters should be posted to the controller along with the file. 'format': 'json' ensures that the wants.json block is invoked in the controller, instead of the default wants.html. This helps the controller to separate Flash uploads from ordinary uploads. The two other parameters in scriptData will be explained later in the article, is they are the key to get the uploading past security and authentication measures taken. fileDataName extracts the name to use for the uploaded file (e.g. asset[:uploaded_data] for attachment_fu) directly from the fallback form. onComplete makes an ajax get request through jQuery to the same url we are currently on. I use this to render some javascript that updates the page in a wants.js in the controller.
There are several gotchas when you upload files through Flash. The most common one, which also apply to ajax, is the infamous ActionController::InvalidAuthenticityToken exception. You will get this exception on any default Rails installation with authenticity checking enabled. Rails expects any post to an action the include the authenticity_token parameter. It is used to verify the post actually came from the same application, and Rails automatically adds to all the forms and ajax requests it generates. In this case, we have to apply it manually, and this what happens with 'authenticity_token': encodeURIComponent('<%= form_authenticity_token if protect_against_forgery? %>'). The form_authenticity_token returns a valid token, but first we check if forgery is enabled. If it is disabled (which it usually is in tests), we will get an error if we invoke form_authenticity_token. encodeURIComponent makes sure that any characters in the token is encoded correctly. With this parameter, we should be able to make an authentic post through Flash – or maybe not …
Rails use data in the user session to authenticate requests, and requests directly from Flash does not include the session cookie that Rails use to find the session. Thus we still get the ActionController::InvalidAuthenticityToken exception, even with the authenticity_token parameter added. We have to make a slight hack into how Rails handles sessions to make this work. Place this code in a file in config/initializers to apply the hack, which tells Rails to try to read the session id from a parameter, if it can’t find in a cookie. This will only happen, however, if we add the line session :cookie_only => false, :only => :create to the asset controller. Also, we must supply the session in a parameter, which is what '<%= Rails.configuration.action_controller.session[:session_key]%>': '<%= u session.session_id %>' } do. The unique session key of the application is taken from the Rails configuration, and the session id is taken from session.
With these measures in place, Rails can now properly authenticate our Flash upload request as a legal, secure post. As an added bonus, actions protected behind session-based logins now also just works. And I would guess that most applications require their users to register and login before they can upload files.
Finally, here is a trick if you use http basic authentication e.g. for the administration tool like we do on Lokalebasen.dk. Place an is_admin? flag in the session, as shown in the code below. This will allow even Flash uploads to be authenticated, even if they don’t supply http basic authentication information:
Hello, I'm Casper Fabricius. I have developed for the web for 9 years, and have been enjoying Ruby on Rails for the past 4.
My experience covers communities, shopping solutions, multi-language sites, heavy back-end lifting and a wide selection of more traditional websites. I like to integrate Ruby with Java and .NET through JRuby and IronRuby when it makes sense. I am passionate about test- and behavior-driven development, but at the same time I am pragmatic and believe in getting things done.
I am based in Copenhagen, Denmark, but I take assignments from across the globe. Feel free to study my resumé, featured projects and - of course - to hire me.
buy paxil canada
buy viagra without a prescription
cheap levitra online
cheap discount soma
buy viagra pharmacy online
cheap discount levitra online
premarin
buy viagra now online
buy legal fda approved viagra
cheaper viagra levitra cyalis
buy medved viagra
discount viagra brand drug
discount viagra in the usa
buy viagra softtabs
buy viagra on line
buy cheap generic viagra
buy online viagra securely
buy viagra next day delivery
cheap online pill viagra
buy lasix
viagra canada prescription
viagra and cialis and
buy discount zoloft
cheap crestor online
buy buy cheap viagra
cheapest price for viagra
cheap pill viagra
buy sildenafil viagra
buy in online uk viagra
cheap cialis viagra
cheap drug retin viagra wellbutrin
order viagra licensed pharmacies online
buy viagra from brazil
cheapsest viagra online
cheap order prescription viagra
buy form generic viagra
buy viagra at safeway
cheap deal discount viagra viagra
cheapest viagra online in the uk
cheapest viagra uk
buy hgh now
buy crestor now
buy viagra in the philippines
buy generic online viagra
cheapest online viagra
order forms for buying viagra
cheapest generic silagra viagra
buy caverta
buy cheap cialis
buy now online viagra
buy cialis canada
buy viagra online 350
order prescription viagra
discount viagra sale
buy viagra from an online pharmacy
order generic viagra
cheap cheap viagra
cheap cheap herbal viagra viagra viagra
viagra by mail order
buy viagra low cost
order viagra usa
cialis 32
buy cheap soma
buy viagra cialis
cheapest viagra in uk cheap
buy online online pill viagra viagra
buy internet viagra
cheap online pharmacy viagra viagra
buy cheap discount levitra
cheap online purchase viagra
buy viagra onlines
buy real viagra pharmacy online
cheapest cialis
buy viagra and cilas usa
buy viagra online order
over the counter viagra in europe
cheap viagra online uk
viagra bullshit
buy viagra online 35008 buy
buy drug satellite tv viagra
viagra breathing
cheap generic india viagra
buy discount viagra online
cialis 1
buy crestor online
discount viagra cialis
buy viagra meds online
buy viagra ups
buy online viagra viagra
soma online
buy generic viagra online pharmacy online
buy viagra online without prescription
cheap viagra kamagra
cheap quality viagra
cheep viagra from indea
buy viagra inte
buy viagra online u
order viagra on line
buy pharmaceutical viagra
viagra and discovery
buy viagra levitra alternative lavitra
cheapest in uk viagra
buy herbal viagra
order viagra onlines
viagra buying online
buy viagra and overseas
buy cheap viagra on the net
cheapest brand viagra
cheap levitra online
buy hgh canada
buy cheap deal pill viagra
order viagra buying viagr
buy plavix
discount viagra generic
viagra buy viagra
buy viagra for cheap
buy viagra in england
buy deal herbal viagra viagra
cheap referrers total viagra
buy cheap cialis generic levitra viagra
order site viagra
cheapest viagra us pharmacy
buy viagra online australia
buy viagra for women
buy kamagra
discount viagra mastercard
cheap discount viagra
cheep generic viagra
buy isoptin
cheap viagra discount viagra buy viagra
buy cialis without prescription
cheap viagra uk
cheapest viagra world
discount viagra viagra
buy viagra in the uk
buy viagra per pill
discount viagra or cialis
cheap overnight viagra
buy viagra now
discount viagra drug
buy lipitor
order order viagra
buy viagra order viagra
discount viagra offers
buy p viagra
cheap kamagra uk viagra
cheapest viagra online plus zenegra
cheap viagra 25mg
buy viagra without prescription
buy in uk viagra
buy generic viagra pharmacy online
buy levitra viagra online
cheap molde ticket viagra
cheapest price viagra
cheapest viagra us licensed pharmacies
viagra and coupon
buy viagra viagra online
order viagra with mastercard
cheap no prescription viagra
cialis online
buy viagra online web meds
viagra buy uk
cheapest price for viagra and cialis
viagra and cialis cheap
generic soma
buy cheao cgeap kamagra uk viagra
buy levitra online viagra
buy prescription viagra without
buy viagra no prescription
buy cheapest online place viagra
buy viagra online online pharmacy
purchase levitra
buy levitra now
purchase levitra online
order levitra online
cheap viagra no presrciption 50mg
buy viagra where
buy online p viagra
buy online purchase viagra
buy viagra 100mg
cheapest generic viagra caverta veega
buy cheap viagra 32
buy online viagra in the uk
viagra by mail
purchase tramadol online
discount viagra prescription drug
buy cheap site viagra
buy viagra zenegra
buy softtabs viagra
over the counter viagra substitute
order viagra online consumer rx
cheap levitra viagra href foro forum
viagra buy it
buy cheap crestor
buy viagra or cilas
order mexican viagra
buy now viagra
buy crestor
buy viagra australia
cheap mexico viagra
buy viagra online india
order viagra online a href
cheap viagra canada
cheapest generic viagra and cialis
buy viagra online no prescription
cialis 20mg
allegra d
cheap deal pill pill viagra
buy viagra online now buy viagra
viagra buy now pay later
buy lexapro
buy viagra alternative
cheap phizer viagra
viagra buy in uk online
order crestor
cheap drug online prescription viagra
generic zoloft
imitrex
buy deal deal price viagra
buy viagra in uk
viagra and deafness
buy viagra cheap through online sales
cheap prescription viagra without
cheap viagra in uk
buy viagra 32
cheap testosterone viagra href foro
buy keyword viagra
order zoloft online
cheap generic viagra substitutes
buy discount soma
buy viagra contact us page
buy canada viagra
buy viagra in mexico
buy australian viagra
cheapest line viagra
order discount viagra
cheap pharmaceutical viagra
order 50mg viagra
viagra buy contest
buy levitra
buy viagra online discount
tramadol cod
cheapest generic viagra and cialis pills
buy viagra online alternative viagra
order crestor online
buy viagra over the counter
buy dot phentermine viagra
buy deal viagra
cheap online generic viagra
buy online sale viagra
buy viagra cheap fed ex
buy avandia
buy glucophage
buy viagra in spain
cheapest prices on generic viagra
buy non prescription generic viagra paypal
zoloft online
cheap meltabs viagra
buy cheap discount lexapro
order viagra softtabs
buy viagra buy cheap viagra index
buy cipro
cheap genric viagra online
generic levitra
buy viagra toronto
cheaper viagra
buy depakote
buy free viagra viagra
buy cheap uk viagra
viagra buy general
cheap viagra cialis
cheap discount soma online
cheap generic viagra from usa
purchase crestor online
buy cheap discount pill viagra viagra
seroquel
cheapest viagra on line
buy viagra safeway pharmacy
buy cheap viagra online uk
cheap soft tab viagra
order status viagra
cheap testosterone viagra href foro forum
cheap drugs viagra cialas
buy now soma
buy crestor
cheap discount cialis
order pfizer viagra with mastercard
cheap viagra credit
cheapest generic substitute viagra
viagra buy australia
cheap viagra online order viagra now
buy viagra in bangkok
buy viagra over the counter us
buy cheap viagra online now uk
buy cheap purchase uk viagra
cheapest viagra and regalis
cheapest generic viagra 99 cents
buy cailis viagra singapore
cheapest viagra prices uk
cheap crestor
purchase crestor
order viagra prescription
viagra and flomax
buy followup post viagra
buy generic viagra online
buy online online viagra viagra
viagra buy
purchase paxil online
order viagra now
cheap viagra
buy carisoprodol no prescription
purchase nexium online
order viagra online in wisconsin
buy in spain viagra
cheap viagra index
over the counter viagra alternative
buy sublingual viagra on the internet
buy imitrex
order viagra overnight shipping
cheap viagra online prescription
buy cheap p viagra
buy viagra with paypal
viagra canada price
buy viagra line
cheap cheap viagra viagra
buy viagra in london
viagra by money order
discount viagra overseas
viagra by phone
buy viagra in toronto
buy cheap levitra
cheapest place to buy viagra online
check generic order pay viagra
buy uk viagra
cheap viagra from pfizer
buy online pill viagra
buy generic viagra si br
buy pill price price viagra
buy generic viagra usa
cheap gerneric viagra
buy cheap online prescription viagra
cheaper viagra levitra apcalis
buy cheap viagra online here
buy viagra phentermine online pharmacy
buy discount price sale viagra viagra
buy discount crestor
buy viagra online cheap
viagra buy do nu
buy viagra by pill
over the counter viagra
buy cheap viagra online now
buy evista
cheap herbal sale viagra viagra
buy cheap lexapro
buy viagra online 35008 buy viagra
buy viagra without prescription pharmacy online
lexapro side effects
buy cheap free online viagra viagra
buy cheapest viagra
cheap discount levitra
cipro 20
cheap viagra fast shipping
relafen
buy online prescription viagra without
buy can reply viagra
buy site viagra
cheap deal viagra
buy online order viagra
cheapest uk supplier viagra
buy viagra in amsterdam
cheapest viagra in uk che
buy cheap sale viagra
order viagra online no rx prescription
buy soma
discount viagra
buy diet viagra online
buy neurontin
buy viagra new york
buy now hgh
cheap discount crestor online
buy online viagra viagra viagra
cheap paxil online
buy levitra canada
buy prescription viagra
discount viagra perscription drug
cheap herbal viagra viagra viagra
buy cheap online uk viagra
buy viagra in united kingdom
buy cheap viagra viagra
buy coumadin
viagra and cialas
cheapest viagra on the internet
cheap discount crestor
cheapest generic viagra sent overnight
buy viagra online get prescription
buy locally viagra
viagra by mail catalog
cheapest viagra overnight
Rasmus Greve
March 26th, 2009 at 4:51 pm
Great post.
Good insight into possibilities concerning user experience.
Uploading and contributing is all the rave :-) – easy, cheap and beautiful implementation is the key for being able to apply uloading solutions over a wide array of applications..
And here is the reason I commented:
You gotta a love the language :-)
”
end
end
end
end
end
“
Casper Fabricius
March 27th, 2009 at 1:24 pm
Are you being ironic, Rasmus? :)
Btw, you can write } } } } } instead of all the ends if you prefer – Ruby allows for both notation forms. But you’d probably rather not have to write anything at all – but where would that leave the poor compiler? ;)
Rasmus Greve
March 31st, 2009 at 12:01 pm
Not ironic when commenting on UX possibilities and as you pointed out, I’m not in a position to discuss syntax or semantics of a high level programming language. :D
I just liked the:
end
end
end
end
end
keep up the good work.
Lars O. Overskeid
March 31st, 2009 at 3:42 pm
For en example of how to resolve the InvalidAuthenticityToken problem without patching, check out http://thewebfellas.com/blog/2008/12/22/flash-uploaders-rails-cookie-based-sessions-and-csrf-rack-middleware-to-the-rescue
The blogpost explains a middleware-approach with rails 2.3.
Casper Fabricius
April 2nd, 2009 at 1:10 pm
Thanks Lars – this looks really cool. Looks like we are going to have to update Lokalebasen.dk to Rails 2.3 soon ;)
Narendra
May 21st, 2009 at 2:55 pm
how to upload multiple files at a time.
Did
June 2nd, 2009 at 3:13 pm
Nice article, thanks for your work !
Unfortunately, I came through a weird bug with “special” characters (such as ‘+’) in the form authenticity token. On the server side, when I get the token, ‘+’ characters for instance are removed. I’m pretty sure it’s caused by the flash component since I use encodeURIComponent.
Have you met this bug before ?
Casper Fabricius
June 2nd, 2009 at 8:14 pm
I actually think I have – I just don’t remember what I did about it, to be honest. It works for me with the above solution, though.
Did
June 3rd, 2009 at 9:53 am
Thanks Casper, I took a look at the action script code and I saw a call to the “unescape” method on the scriptData variable (used by the uploadify query). Perhaps, they changed it for the current reelase. So, next step: remove this call and re-compile the flash component.
pn
June 8th, 2009 at 9:27 am
@Did
i have the same problem.
i use CGI.escape for convert authenticity_token
it’s work very well when you have a ‘+’ in your token
Brandon Mechtley
July 24th, 2009 at 9:59 pm
Thanks for this! Your method, combined with Rob Anderton’s post using a custom Rack middleware worked out great.
Unfortunately, I’m not exactly sure why, but I had a couple problems (Rails 2.3.2), the first being that I needed to replace Rails.configuration.action_controller.session[:session_key] with ActionController::Base.session_options[:key] (Rails complained that the first session variable was nil), and the second being that I have some discrepancies in my session IDs from session.session_id.
session.session_id gives me an ID something like “2d1c06c075ecd8d7e3d8e2adf2371f06,” which seems reasonable, since as far as I know session IDs are supposed to be 32-byte hashes, but the actual session IDs I get from working form posts are more like, “BAh7CToMdXNlcl9pZGkGOg9zZXNzaW9uX2lkIiUyZDFjMDZjMDc1ZWNkOGQ3ZTNkOGUyYWRmMjM3MWYwNjoQX2NzcmZfdG9rZW4iMWdYRGQ0U29SU1k2NGJuOEY1MWZ6S1U3ZW1ZL0hPR09lVU0wTVUvQWQwbzQ9IgpmbGFzaElDOidBY3Rpb25Db250cm9sbGVyOjpGbGFzaDo6Rmxhc2hIYXNoewAGOgpAdXNlZHsA–e96c3614fb16e404a2e1cbcbaf7a401d97883bbf”
I really don’t have any clue why this happens, as I’m pretty new to Rails, but I was able to fix the problem by using request.cookies[ActionController::Base.session_options[:key]] instead of session.session_id.
Hope this helps anyone having a similar problem.
Brandon Mechtley
July 24th, 2009 at 10:01 pm
Woops. Sorry for destroying the format of your pristine blog with that string :)
Brandon Mechtley
July 24th, 2009 at 10:22 pm
I probably should have thought about this before posting–that’s my entire session, and as I’m storing a great deal extra information in it, I guess it’s important to send the whole thing.
Casper Fabricius
July 25th, 2009 at 9:32 pm
Hi Brandon,
Thank you for your comments – and don’t worry about the design of the blog ;)
I don’t mention it in the article, but that code was made a Rails 2.1.2-based project. There has been made significant changes to how sessions work in Rails 2.3.2, so that’s probably what gave you trouble. I’m glad to hear you still got it working, though – I’ll soon need to use this technique on a 2.3.2 project myself, and I’ll post a followup if I run into the same trouble.
Uploading multiple files with progress indicator using jQuery, Flash and Rails | WithExample
March 19th, 2010 at 5:55 am
[...] Uploading multiple files with progress indicator using jQuery, Flash and Rails January 4, 2010 | Posted by admin http://casperfabricius.com/site/2009/03/26/uploading-multiple-files-with-progress-indicator-using-jq... [...]