RESTful file uploads with CarrierWave
CarrierWave also accepts a StringIO, but it expects a original_filename
method, since it needs it for figuring out the file name and doing the extension check. How you do it changed between Rails 2 and 3, here's both methods:
Rails 2
io = StringIO.new(Base64.decode64(encoded_img))
io.original_filename = "foobar.png"
p.image_file = io
p.save
In Rails 3, you need to make a new class and then manually add original_filename
back
class FilelessIO < StringIO
attr_accessor :original_filename
end
io = FilelessIO.new(Base64.decode64(encoded_img))
io.original_filename = "foobar.png"
p.image_file = io
p.save
Upload file with api and carrierwave
Basically it is based on the tool which is used by the API consumer. If API consumer is using ruby then can consume it by passing File object, or using httmultiparty gem we can upload the file.
For you reference https://github.com/jwagener/httmultiparty. Please let me know if you need more help.
How do I upload a file via Carrierwave over a JSON API?
When an HTML form POSTs a file, what actually happens is a special part of HTTP called a multipart request. Effectively, the file gets "attached" to the request.
The question will be answered by what library you are using to POST the JSON to your api. Attaching a file to a request should be fairly commonplace but not all libraries may support it.
This stack overflow article seems to give some good indications of how to do it.
Carrierwave testing - clean up or separate file uploads?
The location where the files are stored is defined in a Carrierwave Uploader by the method store_dir
. If you need to separate the files created in different environments, the simplest solution is to add Rails.env
to the path:
def store_dir
@store_dir ||= File.join(
'public',
'uploads',
Rails.env,
model.class.table_name.to_s,
mounted_as.to_s,
model.id.to_s
)
end
This will create a path like: public/uploads/production/posts/image/1/image.png
carrierwave multiple file uploads and storing
Add the relevant attributes to your model and introduce a before_save callback.
class Video < ActiveRecord::Base
mount_uploader :video, VideoUploader
before_save :update_video_attributes
private
def update_video_attributes
if video.present? && video_changed?
self.content_type = video.file.content_type
self.file_size = video.file.size
end
end
end
For more details see github
Uploading a raw file to Rails using Carrierwave
This can be done but you will still need your clients to send the orignal filename (and the content-type if you do any validation on the type).
def photo
tempfile = Tempfile.new("photoupload")
tempfile.binmode
tempfile << request.body.read
tempfile.rewind
photo_params = params.slice(:filename, :type, :head).merge(:tempfile => tempfile)
photo = ActionDispatch::Http::UploadedFile.new(photo_params)
@postcard = Postcard.find(params[:id])
@postcard.photo = photo
respond_to do |format|
if @postcard.save
format.json { head :ok }
else
format.json { render :json => @postcard.errors, :status => :unprocessable_entity }
end
end
end
And now you can set the photo using
curl http://server/postcards/1/photo.json?filename=foo.png --data-binary @foo.png
And to specify the content-type use &type=image/png
.
Carrierwave - uploading a file from a string
Your solution of using File.open
would work, but you should verify that the name is valid with File.basename
so someone couldn't pass ../../secret_credentials.yml
and expose info you don't want them to. Also checking it against the list of preset images would be a good idea.
However, you can do this more efficiently by skipping CarrierWave in this case.
Add a new field called library_image
, when someone wants to use a preset image, then you set library_image
, if they want to use their own photo, unset library_image
and upload the photo as normal. Then add a helper method like:
def avatar_url
if self.library_image?
"http://example.com/images/#{self.library_image}"
else
self.picture.url
end
end
This assumes that you can find the preset images at http://example.com/images/[name]
and you are using mount_uploader
in CarrierWave named picture
.
Now anytime you want to display their picture, you would call avatar_url
which will check if it should return the preset URL, or the picture they uploaded.
An example of how you would update library_image
or picture
based on your original question:
if params[:file].is_a?(Hash)
model.library_image = params[:file][:url]
model.remove_picture = true
else
model.library_image = nil
model.picture = params[:file]
end
Related Topics
Displaying Only the First X Words of a String in Rails
How to Use a Branch in a Fork of Rails in a Project with Bundler
How to Access Firefox Extension I Added in Selenium Webdriver
Can't Enter Umlauts in Ruby 1.9.3 Irb
Cant Use Has_Secure_Password, Password_Digest Error
Executing Shell Command in Background from Ruby with Proper Argument Escaping
Converting Date Object to Timewithzone
How to Configure Action Mailer (Should I Register Domain)
How to Create a List of Months Between Two Dates in Rails
Webkit_Server Hangs Periodically When Run from Capybara in Ruby
How Does Ruby Serialization (Marshaling) Work
Activerecord 3.1.0 Multiple Databases
How to Highlight Fields on Rails Validation Errors
@Instance_Variable Not Available Inside a Ruby Block
Why I Can Not Call Super in Define_Method with Overloading Method
Parallel Http Requests in Ruby