I'm developing a Ruby on Rails application that requires file uploading/downloading. For the upload part i used the gem carrierwave since it's very easy to use and flexible. The problem is: once i uploaded the file, i need to know a few things: i.e. if it's a pdf instead of downloading the file i show it inline,and the same goes for an image. How do i get the file extension and how can i do it to send the file to a user?? Any feedback is appreciated Thanks!!
Determine file extension (I suppose a name for mounted uploader is 'file'):
file = my_model.file.url
extension = my_model.file.file.extension.downcase
Then prepare mime and disposition vars:
disposition = 'attachment'
mime = MIME::Types.type_for(file).first.content_type
if %w{jpg png jpg gif bmp}.include?(extension) or extension == "pdf"
disposition = 'inline'
end
(add other extensions if you want).
And then send the file:
send_file file, :type => mime, :disposition => disposition
Once you have uploaded a file, the name is stored in the database. This also includes the extension. Assuming you have a User model with an uploader mounted as asset, then you can get it as:
user.asset.file.extension
As for sending it to the user, if you call user.asset_url, it will give you the URL where the file is uploaded. The user can use that link to get the file. Or am I misunderstanding what you mean by "send the file to a user"?
Related
Using the refile gem, I have uploaded documents (.pdf, .docx, .pptx, etc.). Uploading is fine. When I use attachemnt_url, it produces something like /attachments/...234jksdf2.../document. When I click the link_to, it downloads the document without an extension.
What's happening to make it operate this way? How can I restore my file type sanity?
I was trying to address the exact same issue, this is one approach I tried:
Refile allows you to save additional metadata such as the content_type: https://github.com/refile/refile#additional-metadata. The resulting file content type will be saved as something like "image/png" or "application/pdf".
We can then apply something like
link_to "Download file", attachment_url(#document, :file, format: #document.file_extension)
Whereby
in document.rb
def file_extension
file_content_type.split("/").last.to_sym
end
The only issue is that this doesn't automatically downloads the file, but rather opens it in a new page where you can then download the file. Still looking for better alternatives!
This is what ended up being the correct solution for me.
link_to "Download file", attachment_url(#document, :file, format: #document.file_extension)
def file_extension
require 'rack/mime'
Rack::Mime::MIME_TYPES.invert[document_content_type].split('.').last
end
Let's say I upload a file to S3 using Carrierwave in my Rails application. I need to make sure :
The file is hidden (The actual url to be hidden)
Let a user download the file from a temporarily generated URL which allows only 1 download. If we retype that url it won't let the user download the file
How can I achieve this?
You need to do it code itself. You need to track record of downloaded file.
For this you need to create a table that hold information for user and file that already downloaded.
To hide actual s3 url, You need to first read file in your code from s3 and available that file to user with send_data.
xyz = Xyz.find(params[:id])
data = open(xyz_file_path).read
send_file data, filename: file_name_that_you_want,
type: file_content_type, stream: 'true',
:x_sendfile => true
I'm building a website using Rails and I have a Model with some text type value store in MySQL database, I need to provide a download link for my users to download a "*.txt" file which contains those texts.
what I've tried is to use render :text => my_text but it's kind of ugly and the browser can't start a download .
Not I'm trying to use CarrierWave and mount a output_file to my model , I want to build a method to generate a file from its text value. Any suggestion would be greatly appreciated. Thanks!
send_data 'text to send', :filename => 'some.txt'
Documentation Here
My rails app is having trouble identifying Office 2007 documents (pptx, xlsx, docx); it uploads via paperclip with the application/zip mime-type.
It also appears my system (OSX Lion) is detecting the file as a zip as well.
james#JM:~$ file --mime -b test.docx
application/zip; charset=binary
I've tried adding the following to my initializers/mime_types
Rack::Mime::MIME_TYPES.merge!({
".docx" => "application/vnd.openxmlformats-officedocument.wordprocessingml.document"
})
But with no luck.
Any ideas?
This is browser-dependent. The mime types are set as content type by the browser. This depends on the browser implementation and any possible client-side mime type settings that may exist on the client machine.
I've come to the conclusion that checking for document types isn't reliable via the mime type (i.e. content type) alone. It needs a mix of checking for mime type and file extension. File extension alone is also not that reliable, but the combination of both can probably be made to be reasonably workable.
Sadly, Paperclip out of the box doesn't seem to support validating by file extension, so custom code is needed. Here is what I came up with as a custom validation:
has_attached_file :file, ...
validate :mime_type_or_file_extension
private
def mime_type_or_file_extension
if self.file.present? &&
!VALID_UPLOAD_FILE_CONTENT_TYPES.include?(self.file_content_type) &&
!VALID_UPLOAD_FILE_EXTENSIONS.include?(Pathname.new(self.file_file_name).extname[1..-1])
self.errors.add(:file_file_name, "must be one of ." + VALID_UPLOAD_FILE_EXTENSIONS.join(' .'))
end
end
Where VALID_UPLOAD_FILE_CONTENT_TYPES and VALID_UPLOAD_FILE_EXTENSIONS are two arrays we have defined in an initializer. Our attachment is called "file"
Perhaps something like this could be added to the Paperclip gem as pull request. I'll see if I find the time.
Update (12/23/2011) #Jamsi asked about download. We set the Content-Disposition and Content-Type in the response header in the controller, like so:
response.headers['Content-Disposition'] = "attachment; filename=#{#upload.file_file_name}"
response.headers['Content-Type'] = Rack::Mime.mime_type(File.extname(#upload.file_file_name))
Where #upload is our file (Paperclip) object.
I have a paperclip attachment in one model, but I`m not saving the file in /public, but /assets. And when the user what to open the file I use the send_data() function, which makes the user to download the file.
My question is how can I show the file in other way (not nessecery to download)? So if the file is a image, I will see it directly in the browser without download.
Thanks!
Try:
send_data foo, :disposition => 'inline'
This would tell the browser to just render the content, instead of prompting the user to save it.
… from http://apidock.com/rails/ActionController/Streaming/send_data