Rails' Paperclip gem POSTing instead of PUTting when uploading .zip file - ruby-on-rails

I've got a form (Rails 3.2.8, Paperclip 3.1.4) with two Paperclip attachments for a model with two has_attached_files. One is meant to be an image, the other a generic file, usually a .zip file.
Everything works fine so long as I don't try to upload a .zip file. Uploading a .zip file of any size (original was 80 MB but tried 3 MB to see if it was a size issue) causes the form to POST instead of PUT and Rails throws a routing error.
The form method is POST but has the Rails' hidden _method value set to 'put', which works fine and does cause a PUT when I'm not trying to upload .zip files.
The form does have the enctype 'multipart' bit set correctly.
Any idea what could be causing this?

The file sounds large. Double check that the actual params are making it into the request. I get this on local as well depending on the size of the files.
The effect I've seen is that rails would basically get no params. Since a PUT is actually a post with a hidden element, rails would see only the POST since params are dropped.
I am actually not sure what is causing this. I think it may be the local webserver, so you may need to configure nginx or something. This never happens to me on heroku or anything, but always on local if the file is big enough.
Also note, webrick has a really really small size of the request payload limitation. So don't use that. Use "thin" as it is a really easy replacement.

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.

How does finger print digest gets calculated in Rails 4.2

I am using Rails 4.2 and the document states that the fingerprint is an md5 digest calculated based on the content of the compiled file.
If we take a file lets say application-4c697a2e67b1a921abbdc1f753c465d8.js, 4c697a2e67b1a921abbdc1f753c465d8 is the md5 digest. The problem is that we are never able to get the same value by generating md5 from the content of the same file.
I have read somewhere that this fingerprint is not only based on the file but also affected by the environment along with the version of sprockets.
Can someone explain or list down the things (apart from the content of the file) that are used to generate this fingerprint ? And if someone can add a reference from rails sprockets repo (preferably sprockets 2.12.5) that would be very helpful.
The digest seems to be built here: https://github.com/rails/sprockets/blob/master/lib/sprockets/digest_utils.rb
Looks like there's a lot of logic in there, but that's where to find the answer.
It appears that the actual hash is created by calling ADD_VALUE_TO_DIGEST[obj.class].call(obj, digest) in the build_digest method.
Good question; I learned something while looking this up.
This is true for Rails 4.2.x not sure about other versions
There are three parts (concatenated in the same order) involved in generating an md5 against a file.
Sprockets::VERSION.
Rails.application.assets.version that is generated here (https://github.com/rails/sprockets-rails/blob/2.x/lib/sprockets/railtie.rb#L91).
Compiled file content.
The actual digest calculation in sprockets 2.x (for bundled assets) is being done here BundledAsset#L30

Prawn PDF: how to add images uploaded with dragonfly

I like to generate PDF-Files which also includes images uploaded by the user. The prawn gem works so far, and can also embed images located in the file system.
My problem is that I want to include user uploaded images, and where these images are stored will probably change in the future (from file system to some cloud service).
I use the dragonfly gem for handling the images, this uses rack to access the images and sometimes process them on the fly.
Now the simpliest idea does not work
(with report being my object and spot_image my image field)
image report.spot_image
no implicit conversion of #<Class:0x007fc07ecf1110> into String
I tried also to open the file via http with open-uri. This should work, but it blocks on my development machine, I think because the development rails server is single threaded:
image_path = report.spot_image.remote_url
image_url = "#{view.request.protocol}\#view.request.host_with_port}
/#{image_path.sub(/^\//,"")}"
image open(image_url) # timeout in development-mode
It may probably work in production, but even then it does a needless http-request. Can I ask dragonfly (or rack) directly for the image? prawn uses duck-typing and needs some object that responds to read and rewind as image.
I found relevant documentation about dragonfly file handling. The following did not work:
The report.spot_image.data method returns the image data as string, but prawn recognizes the data as path instead of as image data. The dragonfly tempfile method returns a closed temporary file, but prawn does not recognize that it can open it.
I had success with the file method, which returns an open file handle. It is unclear if prawn is closing this file than. So I used the block-style method to make sure the file is closed:
report.spot_image.file do |f|
image f
end
This works so far. (not yet tested with cloud storage)

Creating PDF from photos on a Facebook Rails app

I'm creating a Facebook app using Rails and hosted on Heroku and I'm having a bit of trouble finding the ideal way to solve a problem. I want the user to be able to move their photos around on the screen, position them, and then download that as either a PDF or a PNG file to be emailed or printed. I have the app getting the user's facebook photos and they can drag them on to a HTML5 Canvas element to position them. Taking this canvas, however, and converting it into something printable is where I'm hitting a dead end.
Basically I have a few ideas I have tried:
Convert the Canvas to a PNG using toDataURL() - Would work perfectly but since the photos are external, the canvas is "dirty" and will throw up a security issue. I've thought about trying to copy the pixels of each image to a pixel array but I've heard this may not work either due to security issues. Since the app is dealing with people's facebook images I really don't want to store them on the app's server.
Use PDFKit/wkhtmltopdf to create a PDF using Rails - I've tried this, but since the app is a Sinatra app (I think), it's confusing me a lot. It's throwing errors with the to_pdf call saying 'Command Failed'. I've tried adding a config.middleware.use line but I'm not 100% sure where to put it and everywhere seems to be failing saying "config" is an undefined variable. Also installing wkhtmltopdf seems to fail on Heroku once I test it outside localhost.
Use Prawn to create a PDF using Rails - I've tried prawn but it seems to have a similar problem to PDFKit and I get confused about what goes where on a Sinatra app. I'm sure I read as well that people were having problems with it too.
Have I missed any obvious solutions to this, or is there something I'm not thinking of? All I want to do is create some kind of easily printable file with positioning intact that can be easily downloaded and printed by the user but I've come across so many problems that I don't know where to go next and I'm going round in circles.
If anyone had any advice for me about how I could get around this problem I'd really appreciate it.
if prawn is giving you grief just use one of the jquery plugins to print your div content. You could even configure a pdf printer and print the document instead of hard copy if you so wish/need images in pdf format.
I use http://archive.plugins.jquery.com/project/jqPrint plugin in one of my projects and it works like a charm.
It sounds like many of your issues relate to the necessary PDF binaries not being accessible on Heroku. In following with the twelve factor approach to dependency isolation Heroku purposely provides a very bare system.
If you need to run a custom binary on Heroku I'd suggest looking at a tool called Vulcan which can compile a binary that's compatible with the Heroku runtime.

Static asset caching on Heroku with Jammit by changing ActionController::Base#page_cache_directory

I'm attempting to use Jammit for packaging CSS and JS for a Rails app deployed on Heroku, which doesn't work out of the box due to Heroku's read only file system. Every example I've seen of how to do this recommends building all the packaged asset files in advance. Because of Heroku's Git-based deployment, this means you need to make a separate commit to your repository every time these files change, which is not an acceptable solution to me. Instead, I want to change the path that Jammit uses to write the cached packages to #{Rails.root}/tmp/assets (by changing ActionController::Base#page_cache_directory), which is writable on Heroku.
What I don't understand is how the cached files will be used without hitting the Rails stack every time, even using the default path for cached packages. Let me explain what I mean:
When you include a package using Jammit's helper, it looks something like this:
<%= include_javascripts :application %>
which generates this script tag:
<script src="/assets/application.js" type="text/javascript"></script>
When the browser requests this URL, what actually happens is that it gets routed to Jammit::Controller#package, which renders the contents of the package to the browser and then writes a cached copy to #{page_cache_directory}/assets/application.js. The idea is that this cached file is built on the first request, and subsequent requests should serve the cached file directly without hitting the Rails stack. I looked through the Jammit code and I don't see how this is supposed to happen. What prevents subsequent requests to /assets/application.js from simply routing to Jammit::Controller again and never using the cached file?
My guess is that there's a Rack middleware somewhere I'm not seeing that serves the file if it exists and forwards the request on to the controller if it doesn't. If that's the case, where is that code? And how would it work when changing ActionController::Base#page_cache_directory (effectively changing where Jammit writes cached packages)? Since #{Rails.root}/tmp is above the public document root, there's no URL that maps to that path.
Great question! I haven't set this up myself, but it's something I've been meaning to look into, so you've prompted me to do so. Here's what I would try (I'll give a shot myself soon, but you are probably going to beat me to it).
config.action_controller.page_cache_directory = "#{Rails.root}/tmp/page_cache"
Now change your config.ru to:
require ::File.expand_path('../config/environment', __FILE__)
run Rack::URLMap.new(
"/" => Your::App.new,
"/assets" => Rack::Directory.new("tmp/page_cache/assets"))
Just make sure not to have anything in public/assets, since that won't ever be picked up.
Notes:
This is for Rails 3. Not sure of the solution under Rails 2.
It looks like Rack::Directory sets cache control headers to 12 hours so Heroku will cache your assets to Varnish. Not sure if Jammit sets this in its controller, but even if it doesn't, it will be cached quite quickly.
Heroku also sets ENV['TMPDIR'] now as well, so you can use that instead of Rails.root + '/tmp' if you wish.
This might be of use, it's for a different gem but the idea is similar and I'm trying to get it working with the plain asset helpers.
http://devcenter.heroku.com/articles/using-compass
Unfortunately it seems to be quite difficult to get rails to do this without patching/rewriting the asset helpers module (which resembles coupled spaghetti).

Resources