Rails: Retrieving JPG instead of HEIC from Cloudinary - cloudinary

I'm currently working on a Rails 6 application using ActiveStorage where I'm trying to render images as jpg. I'm using Cloudinary to render the images. I'm trying to support .HEIC images in my web app. A user can upload HEIC images to Cloudinary but I would like for my application to render the image as jpg
When I render the image I see that the browser is rendering the HEIC image which is not supported by browsers.
ActiveStorage uploads the image to the cloud:
Redirected to http://res.cloudinary.com/XXXXXXXXX/image/upload/xxxxxxxxxxxq3r4.HEIC
Completed 302 Found in 24ms (ActiveRecord: 16.1ms | Allocations: 2588)
[ActiveJob] [ActiveStorage::AnalyzeJob] [ac0d5880-xxxxxxxxxxxxxxxxxxxxxxxxxx] Cloudinary Storage (338.6ms) Downloaded file from key: kjpith3bxxxxxxxxxxxxxxxx
[ActiveJob] [ActiveStorage::AnalyzeJob] [ac0d5880-a243-4fef-xxxxxxxxxxxxxxxxxxxx] Skipping image analysis because ImageMagick doesn't support the file
However, I try to render the image from the views as jpg using the following.
<%= cl_image_tag(url_for(post.image), :format => :jpg , class: "card-home__img") %>
But the image is still calling the HEIC image format from this url:
https://res.cloudinary.com/artsyspace/image/upload/v1584732132/wbnknx9ighl6p4ok072u7kd8r5og.heic
Instead of calling the jpg
https://res.cloudinary.com/artsyspace/image/upload/v1584732132/wbnknx9ighl6p4ok072u7kd8r5og.jpg
How can I configure Cloudinary and ActiveStorage to render images or convert images to jpg?

Weirdly, the documentation in one place says the argument is fetch_format, while another shows an example using format.
Worst case, if you're having trouble with the cl_image_tag helper, you can write your own to construct the URL with a .png extension.
https://res.cloudinary.com/artsyspace/image/upload/v1584732132/wbnknx9ighl6p4ok072u7kd8r5og.jpg

It looks like you are sending the full url to the cl_image_tag method.
The cl_image_tag needs just the public id to generate the url.
So the call should be:
<%= cl_image_tag("wbnknx9ighl6p4ok072u7kd8r5og", :format => :png , class: "card-home__img") %>
Of course, make sure to change the hardcoded public id above to the variable holding the public id.
You can get the public id of the resource in the response of the upload.
And one note on the difference between Cloudinary's format and fetch_format:
format would change the extension of the resource i.e
Cloudinary::Utils.cloudinary_url('sample', :format => "png")
will produce https://res.cloudinary.com/demo/image/upload/sample.png
while using fetch_foramt will change the format using the relevant flag, i.e
Cloudinary::Utils.cloudinary_url('sample', :fetch_format => "png")
which will produce https://res.cloudinary.com/demo/image/upload/f_png/sample
In this specific case, both would produce the same png image, but using fetch_format would allow using one of Cloudinary's best features which is optimizing the image automatically using :fetch_format => "auto": https://res.cloudinary.com/demo/image/upload/f_auto/sample

In Rails 6, .key will return the Cloudfare's image ID.
<%= cl_image_tag(post.image.key, :format => :jpg , class: "card-home__img") %>

Related

How do I get dimensions from a CloudinaryPreloadedFile

I need to save the dimensions of my images in my database to help me render images in a pinterest style gallery format.
I use to have this method:
def update_asset_attributes
if image.present? && image_changed?
ap image.file
self.image_content_type = image.file.content_type
self.image_file_size = image.file.size
self.image_width, self.image_height = `identify -format "%wx%h" #{image.file.path}`.split(/x/)
end
end
But now it says: NoMethodError - undefined method content_type for #<Cloudinary::CarrierWave::PreloadedCloudinaryFile:0x007f9834d81840>:
CloudinaryPreloadedFile doesn't have this information at the moment. You can either -
Pass the information by yourself from the javascript code to the server (you can use the cloudinarydone callback data.result object).
Use the attachinary gem.
If the number of images uploaded per hour are small, you can use the Admin API to get the resource's information given it's public_id.

CarrierWave multiple file types validation with single uploader

How to validate the extension of uploaded file when using single uploader for multiple file type?
I am using the single model namely Asset containing the attribute file. Uploader is mounted on file attribute. Asset model having one more attribute called feature_id. feature_id refers to features like video, audio, etc.
So, how should I validate the file type with multiple extension whitelist depending upon feature_id value?
Using ruby 1.9 and rails 3.2.11
Any help will be greatly appreciated.
Although the answer has been accepted but I've got a better way for this. Try this code.
class MyUploader < CarrierWave::Uploader::Base
def extension_white_list
if model.feature_id == 1
%w(jpg jpeg gif png)
elsif model.feature_id == 2
%w(pdf doc docx xls xlsx)
elsif model.feature_id == 3
%w(mp3 wav wma ogg)
end
end
end
feature_id == 1 means you want to allow just picture uploads, feature_id == 2 means that only documents will be allowed to be uploaded and feature_id == 3 will allow you to upload only audio files.
Hopefully it answers the question. You can add more checks for other types of files.
Define your white list in your uploader as shown in the docs for carrierwave.
class MyUploader < CarrierWave::Uploader::Base
def extension_white_list
%w(jpg jpeg gif png)
end
end
I ran into the exact same use case:
In Asset.rb
Validate the format of the filename
validates :asset_file,
format:{
with: %r{\.(pdf|doc|png)$}i, message: "Wrong file format"
}
Use a regular expression to test the file name:
Here you can play with the regex:
http://rubular.com/r/Z3roRDDXAf
Hope this helps!

Where did my filename extension go in the parameter list

I am following this answer while trying to figure out how to display images located in my app directory Rails 3, displaying jpg images from the local file system above RAILS_ROOT
I've created a controller as shown there, added the match line to routes.rb, and in a test webpage I want to load up an image called test.jpg using the code
<img src="/serve_image/test.jpg" />
But I get an error saying the file <...>/public/images/test was not found.
Then I went and renamed my image so that the .jpg was gone, and then the script found my image and loaded it up as wanted.
Any ideas where the extension went? I am not sure how to debug this issue.
By default, Rails doesn't match dots in a dynamic segment. So for this route:
match '/serve_image/:filename' => 'images#serve'
:filename will only match up to the first dot it finds. So /serve_image/test.jpg will match test as the filename and will think you're expecting a JPG as a response. What you need to do is tell the router that you want to include the dot in the filename, something like this:
match '/serve_image/:filename' => 'images#serve', :constraints => {:filename => /[^\/]+/}
That will match anything except a forward slash, giving you your complete filename in params[:filename]
See the Rails Routing guide section on Dynamic Segments for more info.

Paperclip not saving attachment

I am unable to get Paperclip to save my attachment. Rather than saving a single image (such as an avatar as seems to be the common usage), I need to be able to upload/save multiple files; therefore I have a User model and an Asset model. The file information gets properly stored in the asset table, but the attachment itself is not saved in the filesystem as expected.
My log shows the message:
"[paperclip] Saving attachments."
but the attachment is not saved.
Here's a gist with the details: https://gist.github.com/1717415
It's gotta be something simple that I'm missing...
OK... found the problem and it's now working.
The first issue was my naming of the columns in the asset model. I had used simple names: i.e., :description, :file_name, :file_size, :content_type. What I needed to use was: :upload_description, :upload_file_name, :upload_file_size, :upload_content_type where the 'upload' (or whatever you want to use) is a prefix that Paperclip will recognize.And of course that changed my Asset model to reference :upload not :asset, as in:
has_attached_file :upload
Secondly (and this post Adding :multipart => true throws Undefined Method "name" error was key to understanding this) was that you cannot specify the full column name (:upload_file_name) in your view, just specify the prefix and Paperclip magically understands what you want.
Hope this helps someone else!
Did you install ImageMagick?
Did you added image_magick command_path via initializer?
if not, checkout this answer:
Weird paperclip error message

Rails 3 templates: rendering multiple formats using the same template handler

From a single view file containing e.g. LaTeX code with ERB inserts, I would like to be able to:
render to a LaTeX source file, by evaluating the ERB
render to PDF, by compiling the previous result using a custom latex_to_pdf() function
The first case can be achieved by registering a template handler:
ActionView::Template.register_template_handler :latex, LatexSource
where LatexSource is a subclass of ActionView::Template::Handler implementing call(template) or compile(template).
This allows a view file "action.tex.latex" to be accessed and processed correctly as "controller/action.tex".
The second case seems much harder though:
how can the request "controller/action.pdf" be sent to the template handler as if it was "controller/action.tex", and pass the result through latex_to_pdf() before sending the response to the user?
Many thanks
Couldn't you just register another template handler :pdf whose compile method looks similar to this?:
def compile
latex_to_pdf LatexSource.compile(template)
end
Update:
Ok, right, this results in the need of having the view duplicated (action.tex.latex, action.tex.pdf).
Next idea:
respond_to do |format|
format.latex
format.pdf { render :file => latex_to_pdf(render) }
end
As far as I can remember, render returned the rendered template as String in Rails 2.3.
I don't know how it behaves in Rails 3.
You could experiment with render or _render_template. If this works, we could think about how to make this more dry and comfortable for multiple actions.
I didn’t use it myself (yet), but it looks as if https://github.com/jacott/rails-latex could do the job for you.