Impossible to serve generated images without restarting app with Rails + Passenger? - ruby-on-rails

I have images that are generated by users and written to public/designer/designer_output folder.
In config/environments/production.rb I have
config.serve_static_files = true
config.assets.compile = true
In config/initializers/assets.rb I have
Rails.application.config.assets.paths << Rails.root.join('public', 'designer', 'designer_output')
Yet I can't access the files either by requesting /assets/file_name nor /public/designer/designer_output/file_name
If I restart the server then the files become available only via the /assets/ path. But I need them to be available as soon as they are created without restarting.
If find it odd that I can't access them through the public folder at all.
This is on Rails 4.2.6 with Apache/Passenger
Also I have carrierwave as an upload gem, and it is storing files in public/uploads folder and that works fine.

The public folder is used as the web root for the rails server.
You need to drop public in the path or URL:
<!-- file is at /public/foo/bar.png --!>
<img src="/foo/bar.png" />

Related

Rails - why is /public/assets gitignored when I need this for static imaged

In my Rails (Rails 7) app, I have some small assets (a logo and a favicon), which I want to render in production as well as in development.
I put the assets in /app/assets/images.
Since setting # config.assets.compile = true is not recommended, i run RAILS_ENV=production bundle exec rake assets:precompile. It then builds a whole lot of files (it runs esbuild app/javascript/application.tsx since I have a typescript react app running in this rails app.) and puts them in /public/assets/. But this folder is .gitignored by default. Since the folder is approx 5.5 Mb I can see why. Now, heroku docs tell me to add /public/assets/ to git and then my assets should show, but why then is this directory gitignored by default?
Am I missing something? Should I just remove the dir from my .gitignore file?
Or could I just put the assets in the public folder directly? If so, how do I add an image referencing the public folder in an erb file?
The home for static assets is the /public folder. In a default Rails 7 app you will find some error pages (e.g. /public/404.html) and icons (e.g. /public/favicon.ico) already in that folder. Files in this folder will be available both directly, example.com/favicon.ico, and under the public path, example.com/public/favicon.ico. Serving public files can be disabled, see below.
To answer your sub-question, "how do I add an image referencing the public folder in an erb file?" you need to make sure you tell Rails it's an absolute path, not a relative one somewhere in the asset pipeline. This is done with a leading forward slash.
The following compares including a logo called logo.png when it's stored in app/assets/images vs /public
<%= image_tag "logo.png" %>
<!-- becomes <img src="/assets/logo-1f04fdc3ec379029cee88d56e008774df299be776f88e7a9fe5.png"> or similar -->
<%= image_tag "/logo.png" %>
<!-- note the leading slash. This becomes <img src="/logo.png"> -->
<img src="/logo.png">
<!-- or use plain HTML if you don't need/want to use the helper -->
You can also use sub-directories; /public/images/logo.png would be available at /images/logo.png (or image_tag "/images/logo.png").
The second paragraph of chapter 2 of The Asset Pipeline Rails Guide contians more information. It mentions that this functionality depends on whether config.public_file_server.enabled is set.
In Rails 7 that config defaults to ENV["RAILS_SERVE_STATIC_FILES"].present? in config/production.rb. If you're using Heroku you can check this variable with heroku config:get RAILS_SERVE_STATIC_FILES.
The guide also has more information on how to adjust all this behaviour to have these files served by your upstream web server (e.g. nginx) or from a CDN.
Thanks for the comments, I went with adding the assets to the public folder directly and this works fine. It would be nice though if Heroku would either support a way to generate the assets after deployment by default, or describe an option to do it like I did in their docs.

prevent Rails trying to use the asset pipeline for images in folder /public/images

I use the default Rails behavior for asset precompile on production environment.
Now I have a few hundred product images that is stored in public/images/560 and weekly updated. Therefor I don't want these images in the asset pipeline (otherwise I have to asset precompile everytime the images got updated and restart server, right?).
my products/index view:
<div class="image-holder">
<% if File.file? "#{Rails.root.join('public', 'images', '560')}/#{#product.metauid}_v#{#product.version}.png" %>
<img class="product-image py-5" src='<%= "#{request.base_url}" %>/images/560/<%= "#{#product.metauid}_v#{#product.version}_geopard_560.png" %>' alt="<%= #product.metauid%>_v<%= #product.version %>_560.png">
<% else %>
<%= image_tag("placeholder.png", class: "placeholder") %>
<% end %>
</div>
But the image is not shown. In Chrome Inspector I see HTTP Code 303.
How can I prevent Rails trying to use the asset pipeline for images in folder /public/images?
Therefor I don't want these images in the asset pipeline (otherwise I have to asset precompile everytime the images got updated and restart server, right?).
Yeah. Like user generated images these should not be in the pipeline but just stored in /public or better yet a cloud CDN like S3. The assets pipeline is for assets that can be compiled at deploy time.
You might want to consider using ActiveStorage or CarrierWave that both can handle image resizing as well as placeholders instead of reinventing the wheel.
Note you can still have Rails serve files from /public that are not part of the assets pipeline. If you want an example try localhost:3000/robots.txt. This is really useful in development as you probably don't have NGINX or Apache setup locally to serve the files.
How to disable rails from serving static files depends on your Rails version. Usually this is setup in config/environments/*.rb. The config files for recent versions actually default to false for production so that Apache / NGINX serves the files instead.
The setting is also for the entire /public directory. You can't just set Rails to not serve a single directory.
Rails 4 & 5
Rails.application.configure do
config.serve_static_files = false
end
Rails 6
Rails.application.configure do
# Disable serving static files from the `/public` folder by default since
# Apache or NGINX already handles this.
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
end
This is from the generated config/environments/production.rb file and is you can see defaults to false unless the env var RAILS_SERVE_STATIC_FILES is set (the actual value of the env var doesn't matter).

Rails serving files outside assets folder and public folder

Rails version: Rails 3.2.15
Ruby version: ruby 1.9.3p551 (2014-11-13 revision 48407)
Issue:
My rails app in development mode is serving files from storage folder which is at root level. The file format is pdf and mp4.
By serving i mean if I hit the route directly Eg: http://localhost:3000/assets/file_name.pdf is not throwing error and instead is opening on the browser.
I want to put these files behind authentication and hence tried putting it outside app/assets and public/ folders.
I'm not sure why is it able to serve any file outside those directories. Here are few of my configs for reference:
config.assets.enabled = true
config.assets.compress = false
config.assets.debug = true
Please help...
You must have a symlink within the assets directory, a setting in the pipeline, a monkeypatch in asset pipelines, or more likely, or the file itself is there's an 'assets' controller or route. Look carefully :)
Turns out there was some code which when you access the files from app/assets copied those to lib/assets as well. Hence, even after deleting the assets from app/assets it was serving a few files from lib/assets
2.2 Asset Organization
Pipeline assets can be placed inside an application in one of three locations: app/assets, lib/assets or vendor/assets.
That's the official documentation for order and organization of assets.

How to handle uploads and logs in Rails when deployed as a .war file?

I am trying to deploy rails on jRuby using a .war file with the help of Warbler (Tomcat) and/or Torquebox 4 (Wildfly). The problem I face is that I don't know how to handle uploads with Carrierwave or Paperclip in this case.
Ideally uploads should be stored outside the war, as it may be replaced with a newer version of the app anytime.
I tried to create a symlink (uploads) in the public directory before I packaged the app as a war file to /home/username/uploads (permissions are set to 777) directory but that doesn't work (I get a 500 error).
Also how can I access the production.log after I deployed the war file? Or where should I place the logs?
UPDATE
I figured out how to config Carrierwave to store uploads outside the war file:
if Rails.env.development?
CarrierWave.configure do |config|
config.root = "/Users/Username/username_uploads/uploads"
end
elsif Rails.env.production?
CarrierWave.configure do |config|
config.root = "/home/username/username_uploads/uploads"
end
end
Now Carrierwave uploads the files without a problem, but I get a 404 error when I try to view them.
I tried to include a symlink inside the war file to the uploads folder but no success. I tried to create it before running warble war, and also after the app was deployed to Tomcat ( inside the app_name folder ).
Any idea how to solve this?
UPDATE 2
I found a working solution here:
Configure Symlinks for single directory in Tomcat
In short:
cd into the exploded war directory ( you can find this under tomcat/webapps ) that tomcat created ( if the name of the uploaded war file is yourapp.war then the directory name will be yourapp in Tomcat 8 ).
Create an uploads folder with sudo mkdir uploads
Create a mount point: sudo mount --bind /path/to/actual/upload/directory/uploads uploads
I haven't yet tested this with Wildfly, but I will later today or tomorrow. If I remember correctly it won't automatically explode war files by default.
I would still like to know additional, simpler, different solutions for the problem though, and also opinions about the solution I found.
Just food for thought on a different approach...
Using a "cloud based" storage service would make the upload and serving of the assets problem go away, it would also make it simpler to scale the app should you ever need a second node,
it would also reduce the need to scale the app because you would effectively delegate the large data operations which ruby traditionally handles badly to a different service
Amazon S3 is an obvious choice, but check out Riak too
I think the problem you are experiencing with this solution:
if Rails.env.development?
CarrierWave.configure do |config|
config.root = "/Users/Username/username_uploads/uploads"
end
elsif Rails.env.production?
CarrierWave.configure do |config|
config.root = "/home/username/username_uploads/uploads"
end
end
is that you are storing the images outside of the rails public folder, and therefore rails cannot serve them anymore. Carrierwave is uploading everything properly as you would expect it to do, and it creates links, relative to the storage dir.
If you would use the default #{Rails.root}/public storage, rails would serve your images, as any content from public is served (also static html or other assets). As Rails doesn't serve these anymore it's up to you to serve them.
Maybe you can just directly serve them through Tomcat (as I have no expertise in Tomcat configuration you have to figure this out yourself). This would maybe even be faster, as the request surpass the rails stack.
By default, Tomcat does not follow symbolic links (due security reasons). To enable this, you have to add the following inside the Host tag in your server.xml:
<!-- Tomcat 7: -->
<Context allowLinking="true" />
<!-- Tomcat 8: -->
<Context>
<Resources allowLinking="true" />
</Context>
See the docs and the latest migration guide.
If you could provide your logs it would be much easier to diagnose the problem (I take it this problem is only in production because you are asking about how to access that log?). Goto the rails app directory and look in log/production.log these log levels are often lower so you may have to configure them to be more informative config/enviroments/prouction.rb should have a config.log.level this is probably set to info set it to debug for more verbose logging.

Can't access files in Public folder

I have put three files in my public folder. One is a HTML file. I can access this through https://domain.com/file.html
When I try to access either of the other two files through the same method (a .ipa and a .plist) it tells me the file is not found - but I definitely uploaded them. I'm sure this is a beginners question but I'm struggling to find an answer. A link in the HTML needs to be able to access one of them and a link in that file (the plist) will direct to the ipa.
I have tried creating routes to the files but that didn't work.
serve_static_assets worked for me. I was running my Rails application in a Docker Container with Puma. No Apache, nor Nginx to serve static assets.
If you have default row in config (actual for Rails 6):
# config/environments/production.rb
config.public_file_server.enabled = ENV['RAILS_SERVE_STATIC_FILES'].present?
You can append fix it to config.public_file_server.enabled = true.
Or append this variable to start command or docker config file:
RAILS_SERVE_STATIC_FILES=1

Resources