I'm working on a Ruby on Rails project that uses Paperclip for file uploads, S3 for storage, and does some back-end image conversion using Blitline. The result of the conversion gives the original and a file called upload.png in my S3 bucket alongside the original.
So, after conversion I've got two files something along the lines of:
myaws.amazonaws.com/mybucket/model_id/original.pdf and
myaws.amazonaws.com/mybucket/model_id/upload.png
Ideally, I would like to keep the original at hand in my bucket case my user needs to download it again, or if we need to do another conversion for some reason.
Is there a method similar to <% = image_tag #attachment.url %> that will specify the file 'upload.png'?
Edit (More info:)
I did attempt <% = image_tag #attachment.url, :format => :png %> though it does not work. Seems as if rails is still trying to pull it up as a PDF
Have you specified a style for your attachment? If you have one, let's say xyz then you can get the url <% = image_tag #attachment.url(:xyz) %>
<div class="img-container">
<%= if #user.image_url.present? %>
<%= image_tag #user.image_url(:main).to_s %>
<%= end %>
</div>
I am using rails 4, and carrier wave to upload photos as mentioned in the rails casts. So I have a column in my db that is called "image", and the above code works without the if statement. When I use the #user.image_url(:main).to_s and it has an image it properly shows the image in the container. I want to upload a standard photo when the user does not provide one. It's located in my assets/images folder.
How can I get the if statement to detect if there is photo present or not in the column image? I have to use image_url if showing the user uploaded photo. Not just image to display the image, and the .to_s is a safety net. Any thoughts or answers?
Thanks!
Thanks to the accepted answer, I did use the suggested carrier wave solution for Rails 4 which is recommended for 3.1 and above. This post helped me get it corrected: Default URL not loading with Carrierwave in Rails
Specifying a default url with CarrierWave should do the trick. This allows for a fallback if no image is currently present.
Example:
def default_url
ActionController::Base.helpers.asset_path "fallback/main/default.jpg"
end
For Rails 5 the one that worked for me is
ActionController::Base.helpers.resolve_asset_path("logos/smthg.png")
returns nil if the asset is absent
and
the asset path if present
👍
Question:
I would like to force link_to to download images and pdfs fetched from S3 instead of opening them in the browser window.
link_to File.basename(asset.attachment.path), asset.attachment_url.to_s
I looked for solutions but the only ones I found are to handle it in the controller using send_file or send_data but these did not work for me. Finally I stumbled upon the solution in Carrierwave sources.
Solution:
This is what works super well. Use 'response-content-disposition' as a parameter to url
link_to File.basename(asset.attachment.path), asset.attachment_url(:query => {"response-content-disposition" => "attachment"}).to_s
Find more options here: https://github.com/carrierwaveuploader/carrierwave/blob/5aec4725a94fca2c161e347f02b930844d6be303/lib/carrierwave/uploader/versions.rb (line 185)
You can default this for all files of a particular uploader by adding a fog_attributes method.
e.g.
# your_uploader.rb
def fog_attributes
{'Content-Disposition' => "attachment"}
end
This works with requests that aren't signed as well!
I'm new to rails, and I'm writing a RESTful website using the CRUD technique. So far I have created three pages, all of which allow the user to create, edit, and delete a row from the database. However, my fourth page will need to include an upload file form, but a) I don't know how the filesystem works with Rails thus I don't know where files should be stored. The file would be around 100kb and couldn't be stored in temporary storage because it will be constantly downloaded. And b) I don't know how to write to a file.
It would be great if you could tell me how to do what I mentioned above - create an upload input on an input form, and to then write the file to a filepath in a separate directory.
Update 2018
While everything written below still holds true, Rails 5.2 now includes active_storage, which allows stuff like uploading directly to S3 (or other cloud storage services), image transformations, etc. You should check out the rails guide and decide for yourself what fits your needs.
While there are plenty of gems that solve file uploading pretty nicely (see https://www.ruby-toolbox.com/categories/rails_file_uploads for a list), rails has built-in helpers which make it easy to roll your own solution.
Use the file_field-form helper in your form, and rails handles the uploading for you:
<%= form_for #person do |f| %>
<%= f.file_field :picture %>
<% end %>
You will have access in the controller to the uploaded file as follows:
uploaded_io = params[:person][:picture]
File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'wb') do |file|
file.write(uploaded_io.read)
end
It depends on the complexity of what you want to achieve, but this is totally sufficient for easy file uploading/downloading tasks. This example is taken from the rails guides, you can go there for further information: http://guides.rubyonrails.org/form_helpers.html#uploading-files
Sept 2018
For anyone checking this question recently, Rails 5.2+ now has ActiveStorage by default & I highly recommend checking it out.
Since it is part of the core Rails 5.2+ now, it is very well integrated & has excellent capabilities out of the box (still all other well-known gems like Carrierwave, Shrine, paperclip,... are great but this one offers very good features that we can consider for any new Rails project)
Paperclip team deprecated the gem in favor of the Rails ActiveStorage.
Here is the github page for the ActiveStorage & plenty of resources are available everywhere
Also I found this video to be very helpful to understand the features of Activestorage
There is a nice gem especially for uploading files : carrierwave. If the wiki does not help , there is a nice RailsCast about the best way to use it . Summarizing , there is a field type file in Rails forms , which invokes the file upload dialog. You can use it , but the 'magic' is done by carrierwave gem .
I don't know what do you mean with "how to write to a file" , but I hope this is a nice start.
Okay. If you do not want to store the file in database and store in the application, like assets (custom folder), you can define non-db instance variable defined by attr_accessor: document and use form_for - f.file_field to get the file,
In controller,
#person = Person.new(person_params)
Here person_params return whitelisted params[:person] (define yourself)
Save file as,
dir = "#{Rails.root}/app/assets/custom_path"
FileUtils.mkdir(dir) unless File.directory? dir
document = #person.document.document_file_name # check document uploaded params
File.copy_stream(#font.document, "#{dir}/#{document}")
Note, Add this path in .gitignore & if you want to use this file again add this path asset_pathan of application by application.rb
Whenever form read file field, it get store in tmp folder, later you can store at your place, I gave example to store at assets
note: Storing files like this will increase the size of the application, better to store in the database using paperclip.
In your intiallizer/carrierwave.rb
if Rails.env.development? || Rails.env.test?
config.storage = :file
config.root = "#{Rails.root}/public"
if Rails.env.test?
CarrierWave.configure do |config|
config.storage = :file
config.enable_processing = false
end
end
end
use this to store in a file while running on local
I seem to be stuck on figuring out the best approach to let a user upload a text file, have my application parse the file, and then return some output via ajax directly back on the same page. Is there an easy way to do this?
I have been using the following and it works wonderfully but I can't get it to work with ajax.
Here is the view file - index.html.erb
<%= form_tag 'log/new', :multipart => true do %>
<label for="file">Please upload a log file to continue</label> <%= file_field_tag "file" %>
<%= submit_tag ('Upload')%>
<% end %>
I am then able to play with the results in my controller using params[:file] just fine but when I add :remote => true to my form it won't let me do any AJAX or run my .js.erb view file, presumably for security reasons since the js can't read the XHR request yadda yadda.
I have also tried CarrierWave and jquery-fileupload-rails gems but I don't want to save it to the database first which carrier wave seemed to want to do and jquery-fileupload seems to do the same. In any event, even if I get the file uploaded/saved to db with one of those gems - how am I able to access the contents like I was able to with my params[:file] approach?
If you want to upload file with AJAX and rails forms you can use remotipart gem:
Remotipart is a Ruby on Rails gem enabling AJAX file uploads with
jQuery in Rails 3.0 and Rails 3.1 remote forms. This gem augments the
native Rails jQuery remote form functionality enabling asynchronous
file uploads with little to no modification to your application.
For me it works with Rails 3.2 as well.
https://github.com/JangoSteve/remotipart
http://rubygems.org/gems/remotipart