Getting filename before saving in ActiveStorage - Rails 5.2.1 - ruby-on-rails

I am trying to get the name of the file uploaded by a user before ActiveStorage goes on to save it. The form is generated using form_with and is shown below:
<%= form_with model: upload do |form| %>
<div class="">
<%= form.file_field :files, multiple: true, direct_upload: true, required: true %>
<%= form.label :files, '', class: 'icon ion-ios-cloud-upload' do %>
<span>click the icon to select files</span>
<% end %>
<div class="actions">
<%= form.submit "Upload", class: "btn btn-primary" %>
</div>
</div>
<% end %>
I have tried accessing params[:upload][files] and calling .original_filename on it as described here but I get the error NoMethodError: undefined method `original_filename' for #<String:0x007fac77fd18c8>.
The file does come back as a string when I inspect the params, so how do I get the filename or how do I get original_filename to work?

I was finally able to get the file name by doing file.blob.filename after the file had been attached.

Based on the ActiveStorage documentation, I found this worked for me:
file.filename.to_s
In my case I have a model with
has_one_attached :file
OP's situation is slightly different and your situation may differ too, so adjust accordingly.
Troy's solution did not work for me as-is. I had to add the .to_s to get the file name instead of an ActiveStorage::Filename object. But I'm not sure why he's using .blob in there. I didn't need it, but perhaps there's a good reason.

You need to add multipart: true to your form.
https://guides.rubyonrails.org/form_helpers.html#uploading-files
The other thing is that if you have multiple files you'll have multiple filenames.
params[:upload][files].each do |file|
file.original_filename
end

Just running
rake assets:precompile
worked for me.

Related

Why does Rails form multiple: true change submitted param form

I'm playing with ActiveStorage and trying to upload some files locally. Everything works great with the code below, but only if I remove multiple: true from the form. When it is on the form, I get an unpermitted param "files" error in the console. The unpermitted param comes from the way the form is submitting the hash.
Without multiple: true the hash lists attachments as an array (this is the working version):
"article"=>{"files"=>[#<ActionDispatch::Http::UploadedFile:0x007fb4e8e287f0
But with it turned on it it removes the array:
"article"=>{"files"=>#<ActionDispatch::Http::UploadedFile:0x007fb4eb07b7d0
What is causing this form behavior and how can I fix it?
I got the code sample from Engine Yard and here is the project code:
<h3>Attach files to this post</h3>
<%= form_with model: #article, local: true do |f| %>
<div class="form-row">
<%= f.label :file_upload, 'Attach a file' %>
<%= f.file_field :files, multiple: true %>
</div>
<%= f.submit %>
<% end %>
<h3>Attached files</h3>
<% #article.files.each do |file| %>
<%= link_to file.blob.filename, url_for(file) %>
<% end %>
When you use multiple: true you need to permit an array explicit in the article_params for :files:
For example:
params.require(:article).permit(:author, :text, files: [])
You can read more under Action Controller
Good luck!

Using Dropzone.js in a file_field within a Rails form

I am trying to use Dropzone.js to upload files within my Rails app.
It seems that if I use the standard setup, the entire form becomes an image upload field. However, my form contains other fields as well. I only want to use Dropzone.js in a file_field area.
Steps I've used are:
Gemfile
gem 'rails-assets-dropzonejs', source: 'https://rails-assets.org'
application.js
//= require dropzonejs
application.css
*= require dropzonejs
_form.html.erb
<%= form_for #activity, html: {class: 'ui form'} do |f| %>
<!-- Fields like this one don't need to be dropzone fields -->
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<!-- The following field does -->
<div class="field">
<%= f.label :gallery_images %>
<%= f.file_field :gallery_images, multiple: true, class: 'drop' %>
<%= f.hidden_field :gallery_images_cache %>
</div>
<% end %>
activities.coffee
$ ->
$('.drop').dropzone({ url: "/activities/post" });
As you can see, I'm trying to bind Dropzone to the 'drop' class which I've attached to the file_field. However, this doesn't seem to work correctly and I am seeing no errors in the console.
Anyone have an idea how I'd get Dropzone.js to work for a file_field within a Rails form? Or can I only bind it to the entire form?
Any help is much appreciated! Thanks!
You need to permit the :file param. Most probably there will be code something along the line of
private
def activities_params
params.permit(:name, ...other_params)
end
Add :file to the permit method
private
def activities_params
params.permit(...other_params, :file)
end

uploading empty file goes to edit instead of new

I recently noticed that on my form, if I try to upload an empty file the page will get redirected to edit instead of create. If I try to upload the file with some text in it, the form will direct to create. I couldn't find any indication that this would happen as I create my object every time (it's never persisted). Is there an explanation behind this?
The code looks something like this:
//controller
def upload
#new_cool_file = CoolFile.new
end
//form in upload.html.erb
<%= form_for #new_cool_file, html: {role: "form"} do |f| %>
<div class="form-group">
<%= f.label :file %>
<%= f.file_field :file %>
</div>
<%= f.submit "Submit"%>
<% end %>
I think you do some wrong in the rails routes.rb file , can you please see tutorial about file upload.
https://richonrails.com/articles/allowing-file-uploads-with-carrierwave
http://railscasts.com/episodes/253-carrierwave-file-uploads

Rails, uploading a file using only file_field

I need to upload a file in rails without any gems, so I decided just to use
<%= file_field 'upload', 'datafile' %></p>
without any form and etc. Just file_field and in controller I tried to catch it with
name = params[:upload][:datafile].original_filename
it shows me an error:
undefined method `original_filename' for "me.jpg":String
my params:
"upload"=>{"datafile"=>"me.jpg"}
It seems that I cannot use only file_field alone without any form, can I? Or I should alway include it into a form? If yes, is it possible to do it without using a form?
Please verify you have added multipart: true option in your form_tag or not.
Syntax:-
<%= form_tag '/upload', multipart: true do %>
<label for="file">File to Upload</label> <%= file_field_tag "file" %>
<%= submit_tag %>
<% end %>
if you are not using form you should use FormTagHelper file_field_tag
this might help you FormTagHelper/file_field_tag

CarrierWave and Nested Form Gem Redisplay :: HTML File Input Icon

I'm using CarrierWave and Nested Form Gem. Using the section titled 'Making uploads work across form redisplays' on the Carrierwave github page(https://github.com/jnicklas/carrierwave) I'm able to successfully store the cache so that even if the user makes a mistake then the file is saved. The first time I hit the page and click "Upload File" it works and shows the name of the file as well as a small thumbnail icon indicating the type of file that has been uploaded.
However the file input button is blank upon a redisplay and the icon is gone. However I know it's there because if I submit again with valid information and leave the file input button alone it creates a new resource. Here's a snippet of my code.
<%= nested_form_for #resource, :html=>{:multipart => true } do |f| %>
<p>
<%= f.label :title %><br />
<%= f.text_field :title %>
</p>
<%= f.fields_for :attachments do |attachment_form| %>
<p>
<%= attachment_form.label :file %>
<% if !attachment_form.object.file.path.blank? %>
<% file_info = get_cache_file_info attachment_form.object.file.path %>
<%= image_tag(File.join('/tmp/cache/', file_info[:folder])) #THIS DISPLAY CORRECTLY %>
<% end %>
<%= attachment_form.file_field :file %>
<%= attachment_form.hidden_field :file_cache %>
</p>
<%= attachment_form.link_to_remove "Remove this attachment" %>
<% end %>
<%= f.link_to_add "Add attachment", :attachments %>
<p><%= f.submit %></p>
<% end %>
I'm wondering if I have to edit the HTML file input to display the icon or is there some other Rails Way to take care of this. Also the image_tag display correctly, but for my application having users upload text files so the images aren't very helpful.
Thanks in advance!
Update
I also tried setting the value of the 'input' tag like so:
<%= attachment_form.file_field :file, :value => "#{File.join(file_info[:folder], '/',attachment_form.object.file.identifier)}" %>
and that didn't work either. The value of the 'input' tag is set correctly, but it still shows up as "No file selected"
The CarrierWave introduction doesn't make this very clear, but it sounds like your code is functioning 'correctly'. The cache field just serves to ensure that your attachment will be saved after a valid submission.
This document explains that the file input element's FileList should be read only, presumably for security reasons.

Resources