[Ruby on Rails 4 + Paperclip gem]: Ajax image upload
Estimate reading time: 6 minute
0. why
I was trying to create Ajax Image Upload API for My Rails application,
So I search on Google,
These article:
- 80% from 2011~2013
- not working
- over complex.
I poke around little bit, and come with a simple solution
Here is my solution
0.5 Preview final result:
Well, let’s do this step by step
1. Create a Rails project
ruby
rails new img --skip-bundle
2. Install Paperclip gem:
following instruction come from offcial guide
add following line to gemfile
ruby
gem "paperclip", "~> 5.0.0"
and then
bundle install
or
gem install paperclip
3. Create model for Image and necessary migration
run
ruby
rails g model Image
copy & paste following code into app/models/image.rb
class Image < ActiveRecord::Base
has_attached_file :image, styles: { medium: "300x300>", thumb: "100x100>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
end
rails g migration addAttachmentToImage
inside db/migrate/20160721100726_add_attachment_to_image.rb
file
class AddAttachmentToImage < ActiveRecord::Migration
def up
add_attachment :images, :image
end
def down
remove_attachment :images, :image
end
end
and finally
bundle exec rake db:migrate
4. Routes
config/routes.rb
Rails.application.routes.draw do
# for view
get '/image' => 'test#image'
# for ajax
put 'api/image_upload' => 'api#image_upload', as: :image_upload
end
rails g controller test image
rails g controller api image_upload
5. View
put following content into: app/views/test/image.html.erb
<%= file_field_tag :image %>
<script type="text/javascript">
$('#image').change(function(){
var formData = new FormData(),
$input = $(this);
formData.append('image[image]', $input[0].files[0]);
$.ajax({
url: '<%= image_upload_path %>',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'PUT'
});
})
</script>
6. Controller
in file: app/controller/api_controller.rb
class ApiController < ApplicationController
def image_upload
@image = Image.create(img_params)
if @image
render :json => {:status => 'success',:image_url => @image.image.url}
else
render :json => {:status => 'fail'}
end
end
private
def img_params
params.require(:image).permit(:image)
end
end
7. Experiment Time!
ruby
rails s -b 0.0.0.0 -p 5000
s mean server
-b mean you can visit this outside vmware
-p mean port 5000
7.1 First
http://192.168.1.139:5000/image
your address is different from mine, don’t forget change it
7.2 Let’s Choose a file
7.3 It work!
7.4 Image work!
Done! over.
but we can push little further
Let’s preview file
<%= file_field_tag :image %>
<img id='preview' src="#"> <!-- new code here-->
<script type="text/javascript">
$('#image').change(function(){
var formData = new FormData(),
$input = $(this);
formData.append('image[image]', $input[0].files[0]);
$.ajax({
url: '<%= image_upload_path %>',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'PUT'
}).done(function(result){ <!-- new code here-->
console.log(result.image_url); <!-- new code here-->
$('#preview').attr('src', result.image_url); <!-- new code here-->
}); <!-- new code here-->
})
</script>
if you need validate:
Model
class Image < ActiveRecord::Base
has_attached_file :image, styles: { medium: "160x160>", thumb: "60x60>" }
validates_attachment_content_type :image, content_type: /\Aimage\/.*\Z/
validates_attachment :image, :presence => true,
:size => { :in => 0..2048.kilobytes }
end
Controller
class ApiController < ApplicationController
def image_upload
image = Image.new(img_params)
if image.save
render :json => {:status => 'success',:image_url => image.image.url}
else
render :json => {:status => 'fail', :info => image.errors.full_messages}
end
end
private
def img_params
params.require(:image).permit(:image)
end
end
Conclusion
Most important part is
view:
<%= file_field_tag :image %>
<img id='preview' src="#"> <!-- new code here-->
<script type="text/javascript">
$('#image').change(function(){
var formData = new FormData(),
$input = $(this);
formData.append('image[image]', $input[0].files[0]);
$.ajax({
url: '<%= image_upload_path %>',
data: formData,
cache: false,
contentType: false,
processData: false,
type: 'PUT'
}).done(function(result){ <!-- new code here-->
console.log(result.image_url); <!-- new code here-->
$('#preview').attr('src', result.image_url); <!-- new code here-->
}); <!-- new code here-->
})
</script>
controller:
class ApiController < ApplicationController
def image_upload
image = Image.new(img_params)
if image.save
render :json => {:status => 'success',:image_url => image.image.url}
else
render :json => {:status => 'fail', :info => image.errors.full_messages}
end
end
private
def img_params
params.require(:image).permit(:image)
end
end