Serving dynamically generated images in Rails 6.1 - ruby-on-rails

My application dynamically generates images using the gruff gem and then serves these images. The images are stored in app/assets/images/gruff. The images are altered during runtime (keeping the same filename but altering their contents), since these images contain a bar graph containing information for the user that changes over time. The images are generated if they are missing, and there is no requirement for them to exist for long periods of time. The images are served using image_tag.
The issue is that there are 2 types of intermittent problems that occur. One is that the image link generated will sometimes have the wrong fingerprint, even though the images will have just been updated before the image_tag is rendered. (Thus 404'ing.)
The second issue is that even though I can verify the image exists on the server, I still occasionally get a ActionView::Template::Error (The asset "gruff/image-1.png" is not present in the asset pipeline.):
If this should be working, how can I further dig into understanding what the issue is?
If the asset pipeline is simply not a good mechanism for what I'm trying to do, what would the community suggest instead?

A better idea for your problem is save this generated image with activestorage, so you should create a model like that:
class DynamicImages < ApplicationRecord
has_one_attached :image
end
And create a record when use gruff to generated this image.

Related

True Paperclip Replacement (Speficially Structure of the File System)

With Rails 6, I need to replace Paperclip, but I can't find any substitutions that actually easily replicate it.
Specifically, the file structure paperclip used:
:model/:attachmant_field/000/000/000/:identifier/:style/:original_file_name
Over the last decade we have built several tools that rely on that structure (or something similar) and in addition our users expect that after uploading an image, they can reference the styles with the same file name and a permanent url (not a randomly generated name like ActiveStorage and Shrine does) and change the "style" component in the url to a different one in their html.
I've spent several days both on Shrine and ActiveStorage working to get the file structure and naming to work on and keep failing, as despite being "natural replacements" they don't actually handle things in the same way.
Our end system is on Amazon S3, though integrating with that hasn't been the issue, just the file system.
Thanks for your help, it's been really frustrating having to remove something that works great when there seems to be nothing that actually replaces it, if you want/need things done in the same way. I'd rather not have to start rewriting all of tools that we developed and resetting our customers expectations to work with a new structure.
Thanks so much.
Have you tried Carrierwave? You can specify any storage path and build it dynamically using model name (model.class.to_s.underscore), attachment field (mounted_as), model id (model.id). The original file name is also available as original_filename.

Carrierwave/fog are uploading files to S3, but the app is still trying to use the local path to access images

I know this is a broad question, and I'm biting off a little more than I can chew for a first stab at a rails app, but here I am.
I tried to add an image upload/crop to a basic status app. It was working just fine uploading the images and cropping them with carrierwave, but as soon as I started using Fog to upload to S3, I ran into issues.
The image, and it's different sizes, appear to be ending up on S3 just fine, but the app is still trying to access the image as "/assets/uploads/entry/image/65/large_IMG_0035.jpg"
Locally, it just shows a broken image, but on Heroku it breaks the whole thing because
ActionView::Template::Error (uploads/entry/image/1/large_IMG_0035.jpg isn't precompiled
The heroku error makes sense to me because it shouldn't be there. I've combed through the app but don't know what's forcing this. I'll post any code anybody thinks will work? Thanks in advance!
Clarification:
Just to clarify, the images are uploading to S3 fine, the problem is how the app is trying to display the image_url
The app is using a local path in the asset pipeline, not the S3 path that it's actually uploading to.
I was having the same issue. In my Carrierwave Initializer I was setting host to s3.amazonaws.com but when I removed that line altogether urls started working.
I hope this helps you resolve your issue, I fought this for several hours!
I believe this issue is related to how you are accessing your image in your view.
If you have mounted an uploader on the field avatar in the following manner:
class User < ActiveRecord::Base
mount_uploader :avatar, AvatarUploader
end
You would access it in your ERB as follows:
<%= image_tag(#user.avatar_url) %>
I would also suggest watching the following Railscast on the topic.
http://railscasts.com/episodes/253-carrierwave-file-uploads
Re-reading issue, I bet it has to do with Carrierwave using Herkou.
Give this a glance and see if it helps.
https://github.com/jnicklas/carrierwave/wiki/How-to%3A-Make-Carrierwave-work-on-Heroku
I am not clear what exactly do you want to achieve.
But for now I have 2 ideas:
For assets host in CDN, you can take a look at this:
https://devcenter.heroku.com/articles/cdn-asset-host-rails31
If you want the images to be part of a model-relation, here's my rough idea:
Put the images path in a table column.
For further information about this you can browse carrierwave github site.(It has many docs and tutorial)

image_path always uses assets/ when I want just public/images

Why does image_path insist on appending assets/ to the front of image paths that are stored in public/images?
I'm building a photographer's website, so naturally we want photos to be in it, including a random sub-selection of some photos to be shown as part of the layout. Further, I've built a super-simple gallery that just displays all photos. Those image files are stored in:
public/images/gallery
I've gotten an ImageMagick gem to shrink them to the desired size. Those small files are stored in:
public/images/gallery/sm/
The shrinking is done on page load as part of rendering the layout ERB. I know it might initially sound awful, but it only shrinks an image once, and the lazy-shrinking means we don't have to restart the server to add new photos (which he'd want to do).
My reading suggests that the asset pipeline is for static layout stuff, but this is more dynamic than that. I'm led to believe that public/images is where this stuff should go, especially since production-mode Rails complains that the generated thumbnails are not compiled.
Enter the problem: I place those images in the paths shown above, and image_path gives back what looks like an asset pipeline path. It doesn't even work when I flatten the subdirectories and have everything live in public/images.
My workaround is to build the tag manually. So is image_path (and by extension, image_tag) only for asset pipeline stuff? Am I supposed to construct tags from strings for public images? I've also found mentions that image_path is supposed to look in public for a matching file first, but I've also seen documentation (http://api.rubyonrails.org/classes/ActionView/Helpers/AssetTagHelper.html) claiming that it won't verify the existence of something it returns a path for.
Edit: error in original answer
Rails asset pipeline is for serving assets that are present when the application starts. For serving dynamic assets as you suggest there's this answer to a similar question: Rails 3.1 assets not recognizing new images uploaded by rmagick until server restart which answers far better than my answer just did.
Having searched around to improve on my first answer, I think the best solution to the image_tag creation then is to create your own image_tag-like helper. Perhaps:
def public_image_path(filename)
[your path to that file]
end
def public_image_tag(filename, options={})
image_tag(public_image_path(filename), options)
end

How should I handle the rails asset pipeline for uploaded images that change the scope of their public view?

After reading about how rails is handling image assets, I am confused and am having trouble deciding where to keep uploaded images in my app's directory tree. If a user has uploaded an image to my rails app, should I make the image_save_path /assets/images/ or /public/images ?
My concern/question: If I want to allow users to make their images public when they choose to do so, should an uploaded image that is 'un-published' (image is served only if current_user == image.owner) be considered more protected if it resides in assets/images instead of public/images? Equally protected? Less protected somehow?
Am I right to assume that the benefit of using the asset pipeline for images is simply that the file names get hashed in production mode and that's it? Is there some implied additional or diminished security here in terms of how the resource is served? Is this more a matter of subtle opinion or does the rails convention have something to say here?
Thanks!
EDIT1:
How would you handle uploaded content that you want to make available to the uploading user, but not discoverable to guests or other users? Should (can?) one store uploaded content outside the tree under web_root ?
Application assets are those assets that are part of your application, such as backgrounds and icons (in the case of images). The asset pipeline has nothing to do with user-uploaded images. I'd suggest to keep them separated, serve them from separate CDN if needed.
The hashing of filenames in the asset pipeline is done only during asset compilation, so a link to a specific image is made unique for the image contents. This helps to avoid setting complex caching headers to images and other assets, as when the image changes, the filename changes too, and the cached version won't be used at all.
All this does not apply to user-uploaded images, you are not going to compile on-the-fly the assets for their images.

Which plugins/gems should I use to dynamically generate thumbnails on-the-fly in Rails 3?

So, the thing is. I'm building my first rails app which reads images from a directory and it's subdirs. Now, I want to generate dynamic thumbnails of those images. But I don't want to fill up that directory with the thumbnail images. I was thinking of caching these thumbs separately for each user in temporary directory.
Oh, and, I would also need the dimensions of the images for some css magic.
What plugins/gems/... should I use to accomplish this?
You should rmagick coupled with Paperclip. In this way you can specify the dimensions (and many other attributes of the images), and make thumbnails on the fly.
On top of this, I would also add in delayed_job which will background the process of the images so if any of them are provided by the client, they won't have to wait for it to complete client-side.
rMagick : http://github.com/rmagick/rmagick
Paperclip: http://github.com/thoughtbot/paperclip
delayed_job: http://github.com/collectiveidea/delayed_job

Resources