August 31, 2010
Posted by roadburn
How to upload multiple files on rails (uploadify + paperclip + jquery)
Setting Up
Download Uploadify from
http://www.uploadify.com/
copy the uploadify files into the following directories
1 2 3 4 5 6 7 | public/javascripts/uploadify/jquery.uploadify-2.1.0.min.js public/javascripts/uploadify/uploadify.swf public/javascripts/uploadify/swfobject.js public/images/cancel.png public/stylesheets/uploadify.css |
Create this file
app/middleware/flash_session_cookie_middleware.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | require 'rack/utils' class FlashSessionCookieMiddleware def initialize(app, session_key = '_session_id') @app = app @session_key = session_key end def call(env) if env['HTTP_USER_AGENT'] =~ /^(Adobe|Shockwave) Flash/ req = Rack::Request.new(env) env['HTTP_COOKIE'] = "#{@session_key}=#{req.params[@session_key]}".freeze unless req.params[@session_key].nil? end @app.call(env) end end |
Add this line to
config/initializers/session_store.rb
1 | ActionController::Dispatcher.middleware.insert_before(ActionController::Base.session_store, FlashSessionCookieMiddleware, ActionController::Base.session_options[:key]) |
Make sure your environment.rb file has this
config/environment.rb
1 2 3 4 5 6 7 8 9 | Rails::Initializer.run do |config| config.gem 'mime-types', :lib => 'mime/types' config.gem 'paperclip' %w(middleware).each do |dir| config.load_paths << "#{RAILS_ROOT}/app/#{dir}" end end |
Models
Let’s assume you want to create a photo album with many photos.
Create your photo model with the following:
db/migrate/create_photos.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | class CreatePhotos < ActiveRecord::Migration def self.up create_table :photos do |t| t.integer :attachable_id t.string :description t.string :data_file_name t.string :data_content_type t.integer :data_file_size t.datetime :data_updated_at t.string :parent end end def self.down drop_table :images end end |
In your album model:
app/model/album.rb
1 | has_many :photos, :dependent => :destroy, :foreign_key => :attachable_id |
In your photo model:
app/model/photo.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 | belongs_to :album, :foreign_key => :attachable_id has_attached_file :data, :url => "/assets/images/:id/:style/:basename.:extension", :path => ":rails_root/public/assets/images/:id/:style/:basename.:extension", :styles => { :large => "800x800>", :medium => "300x300>", :thumb => "100x100#"} validates_attachment_presence :data validates_attachment_size :data, :less_than => 2.megabytes validates_attachment_content_type :data, :content_type => ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'] |
Controllers
app/controllers/photos_controller.rb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | class PhotosController < ApplicationController def create newparams = coerce(params) @photo = Photo.new(newparams[:upload]) // so this photo can belong to other models other than album @parent = @photo.parent.constantize.find(@photo.attachable_id) if @photo.save flash[:notice] = "Successfully uploaded photo." respond_to do |format| format.html {redirect_to @parent} format.json { render :json => { :result => 'success', :upload => photo_path(@photo) } } end else flash[:notice] = "Only gif, jpg or png files allowed" respond_to do |format| format.html {redirect_to @parent} format.json { render :json => { :result => 'failed'} } end end end def show @photo = Photo.find(params[:id]) end def coerce(params) if params[:upload].nil? h = Hash.new h[:upload] = Hash.new h[:upload][:attachable_id] = params[:attachable_id] h[:upload][:parent] = params[:parent] h[:upload][:data] = params[:Filedata] h[:upload][:data].content_type = MIME::Types.type_for(h[:upload][:data].original_filename).to_s h else params end end end |
Views
app/views/albums/show.html.erb
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 | <%= stylesheet_link_tag "uploadify" %> <%= javascript_include_tag "uploadify/swfobject", "uploadify/jquery.uploadify.v2.1.0.min.js" %> <%- session_key_name = ActionController::Base.session_options[:key] -%> <script type="text/javascript" charset="utf-8"> jQuery.noConflict(); jQuery().ready(function() { jQuery('#photo_upload').click(function(event){ event.preventDefault(); }); jQuery('#photo_upload').uploadify({ 'uploader' : '/javascripts/uploadify/uploadify.swf', 'script' : '/cms/photos', 'multi' : true, 'cancelImg' : '/photos/cancel.png', onComplete : function(event, queueID, fileObj, response, data) { var dat = eval('(' + response + ')'); if (dat.result=='success'){ jQuery.getScript(dat.upload); }else{ alert("Only .jpg, .gif, .png files under 2MB allowed. ") } }, 'scriptData' : { 'format' : 'json', '<%= session_key_name %>' : encodeURIComponent('<%= u cookies[session_key_name] %>'), 'authenticity_token' : encodeURIComponent('<%= u form_authenticity_token if protect_against_forgery? %>'), 'attachable_id' : '<%= @album.id %>', 'parent' : 'Album'} }); jQuery('#photo_submit').click(function(event){ event.preventDefault(); jQuery('#photo_upload').uploadifyUpload(); }); }); </script> <% form_for Image.new(:attachable_id => @deal.id), :html => { :multipart => true } do |f| %> <div class="image-uploader"> <%= f.file_field :data, :id => 'image_upload' %> <%= f.submit "Upload Images", :id => 'image_submit'%> </div> <% end %> |
Resources
Many thanks to the following articles that helped me figure out how to get this working
Please follow the links for more detailed explanations
http://fencore.posterous.com/uploadify-with-paperclip-on-rails-tutorial
http://timmyc.posterous.com/uploadify-on-rails-with-paperclip
http://www.practicalecommerce.com/blogs/post/432-Multiple-Attachments-in-Rails
http://www.utoronto.ca/web/htmldocs/book/book-3ed/appb/mimetype.html
http://en.wikipedia.org/wiki/Internet_media_type
2 Comments
December 9, 2010
wow, this is awesome!;)
thank you
January 8, 2011
This was very helpful, thanks for posting. Some updates are needed for Rails 3.0, and I had ferreted them out, but then I found a gem that handles all of the Rails side:
https://github.com/trevorturk/flash_cookie_session
Also, to work with the Uploadify 3.0 beta, there are a few changes:
$(‘#photo_upload’).uploadify({
‘swf’ : ‘/javascripts/uploadify/uploadify.swf’,
‘uploader’ : ‘/assets’,
‘checkExisting’: ‘/assets/exists’,
‘cancelImage’ : ‘/images/uploadify-cancel.png’,
‘folder’ : ‘/tmp’,
‘auto’ : true,
‘postData’ : {
‘_http_accept’: ‘application/javascript’,
‘_method’: ‘put’,
‘#{Rails.application.config.session_options[:key]}’ : ‘#{cookies[Rails.application.config.session_options[:key]]}’,
‘#{request_forgery_protection_token}’: ‘#{form_authenticity_token}’
}
/assets/exists is called with: parameters => {filename”=>”hachiko.jpg”} but I haven’t yet decided exactly how to handle it.
Leave a comment