Encode Carrierwave attachment to base64 in Rails - ruby-on-rails

I am using the Carrierwave gem to upload attachments to my model. I added elasticsearch with the mapper attachments plugin to allow for full text search of the attachments.
Carrierwave and elasticsearch work fine, but in order to get the full text search working I need to encode the attachment as base64.
I have followed this tutorial (http://rny.io/rails/elasticsearch/2013/08/05/full-text-search-for-attachments-with-rails-and-elasticsearch.html) but I assume there has been some changes to either Rails or Carrierwave as I can't get it to work. Specifically, when I am trying to encode the attachment as base64, I get the following Type error:
no implicit conversion of CarrierWave::SanitizedFile into String
The error is in the following line of the model:
File.open(Base64.encode64(File.read(document.file)))
If I replace the path with a url to an actual file it works fine.
I have searched SO and the only relevant answer I can find gives me the same error: Carrierwave encode file to base64 as process
I am a complete rails newbie and hopefully this is something that's obvious to everyone except me, but we're all beginners at first, right?
Thanks!

CarrierWave's read method returns the content of the file. So assuming Document is your model and file is your uploader attribute, this should work:
Base64.encode64(document.file.read)

Related

ActiveStorage CSV file force encoding?

I have a CSV file that I'm uploading which runs into an issue when importing rows into the database:
Encoding::UndefinedConversionError ("\xCC" from ASCII-8BIT to UTF-8)
What would be the most efficient way to ensure each column is properly encoded for being placed in the database or ignored?
The most basic approach is to go through each row and each field and force encoding on the string but that seems incredibly inefficient. What would be a better way to handle this?
Currently it's just uploaded as a parameter (:csv_file). I then access it as follows:
CSV.parse(csv_file.download) within the model.
I'm assuming there's a way to force the encoding when CSV.parse is called on the activestorage file but not sure how. Any ideas?
Thanks!
The latest version ActiveStorage (6.0.0.rc1) adds an API to be able to download the file to a temp file, which you can then read from. I'm assuming that Ruby will read from the file using the correct encoding.
https://edgeguides.rubyonrails.org/active_storage_overview.html#downloading-files
If you don't want to upgrade to the RC of Rails 6 (like I don't) you can use this method to convert the string to UTF-8 while getting rid of the byte order mark that may be present in your file:
wrongly_encoded_string = active_record_model.attachment.download
correctly_encoded_string = wrongly_encoded_string.bytes.pack("c*").force_encoding("UTF-8")

How can I identify the kind of file in rackspace?

I gonna upload files to rackspace(video, audio and images) in rails with paperclip or carrierwave, I need to Know the kind of file, to show in the view with image_tag, or video_tag or audio_tag, rackspace tell me the kind of file? or I have to store in my database? thanks
You can query/set the file type by using the 'content_type' function located in the 'ruby-cloudfiles' library.
See here: https://github.com/rackerlabs/ruby-cloudfiles/blob/master/lib/cloudfiles/storage_object.rb#L80-L82
Something like this should work for creating the object:
container = conn.create_container('new_container')
obj = container.create_object('new_obj.txt')
obj.load_from_filename('./obj.txt')
obj.content_type = 'text/plain'
And to retrieve the object:
obj = container.object('new_obj.txt')
puts obj.content_type # text/plain
Even if rackspace would tell you the file type, you don't want it to, since it would take so long to run roundtrips from your server to theirs.
My code examples below assume carrierwave, but I'm sure paperclip has similar options. Two options:
Interpret the file extension
Something like: File.extname(user.avatar), which you then have to interpret however you like.
Record & interpret the mime type.
The carrierwave readme explains how to get carrierwave to calculate it in the first place, and then you should probably store it to your database manually or using carrierwave-meta. Then user.avatar.content_type would be something like image/jpeg which you could easily interpret as a particular file type.

ruby on rails: Convert an image file to byte array

I need to upload an image from a rails form using Ajax and convert it into a byte array to show a html preview of the image.
When I read the file, it returns me binary data which is not readable by img tag. I'm sure I'm doing something very silly and this might have an obvious solution. Here is the code snippet. Please help.
rails
tmp = File.open(params[:file_upload][:my_file].tempfile, 'rb').read
render :text => tmp
jquery
$("#item_detail_image").attr("src", "data:image/png;base64," + data.responseText);
I'm not using paperclip because I don't have a database connection to my rails application (I'm using web services) and I'm not sure how to use paperclip without ActiveRecord
You need to Base 64 encode the data.
See http://www.ruby-doc.org/stdlib-1.9.3/libdoc/base64/rdoc/Base64.html#method-i-encode64

where from does paperclip get the name of original file?

i started using nginx upload module (which creates upload files like /tmp/000121545) but i need paperclip to use original filename while saving files (like /public/avatars/LuckyLuke.jpg)
previously in the parameters Rails were passing just
"avatar"=>#<File:/tmp/RackMultipart20100413-6151-t3ecq0-0>
no original filename as well, so i am wondering where from does it come in paperclip? i tried looking through plugin code but it's currently a bit too complex for me.
The browser sends a http header with the file name. ("Content-Disposition: filename=original_file.jpg")
Rails makes this available as a instance method of the temp file object: params[:avatar].original_filename, and paperclip uses that.
In detail, Rack parses the multipart form in Rack::Utils::Multipart::UploadedFile and puts a hash in the parameters that includes :tempfile and :filename. Then ActionDispatch::Http::Upload comes along and replaces that hash by the File object (value of :tempfile), extending it with the module ActionDispatch::Http::UploadedFile, which adds a instance variable for original_path and the method original_filename.

Using restclient with multipart posts

I'm using restclient for a multipart form to send data to a restful web service (it's Panda video encoding service).
The trick though, is that the file I am passing into restclient (Technoweenie branch) is coming from my own form that a user submits.
So, lets walk through this. A user posts a file to my rails app. In my controller, it receives the file from params[:file]. I then want to pass params[:file] down to Panda using RestClient.
The error I'm getting is on the Panda server follows. I noticed that the file param in the stack trace is in a string as well (which I assume is Panda turning into a string for a nicer stacktrace).
~ Started request handling: Wed Aug 12 18:05:15 +0000 2009
~ Params: {"format"=>"html", "multipart"=>"true", "account_key"=>"SECURE_KEY", "action"=>"upload", "id"=>"SECURE_ID", "controller"=>"videos", "file"=>"#<File:0xcf02ca4>"}
~ 9bfb1750-6998-012c-4509-12313900b0f6: (500 returned to client) InternalServerErrorcan't convert nil into String
/var/local/www/panda/app/models/video.rb:246:in `extname'
/var/local/www/panda/app/models/video.rb:246:in `initial_processing'
/var/local/www/panda/app/controllers/videos.rb:79:in `upload'
I doubt you can really pass a CGI-style upload param from Rails into restclient and expect it to work.
A regular upload in Rails would have quite some extra attributes which do not belong in a posted resource (like the original filename and so on), and a Rails upload contains an IO with the actual file data. Also a file upload object in Rails might be a Tempfile handle and might be a StringIO - depending on the size of the upload.
What you effectively need to do is "repackage" your upload for rest-client to handle it properly, and pass the repackaged and rewound Tempfile object to restclient. Maybe you can get away with just picking the upload object itself instead of the whole params[:file]
Confirm that your restclient action can save locally first. If the action cannot save locally, then you will have a better idea where to look while trouble shooting.
Looks like the problem is with rest-client's posting of the file, check out an alternative method for posting like curb.
Lots of examples for posting multipart form data on this question: Ruby: How to post a file via HTTP as multipart/form-data?

Resources