I want to embed a file input field in my form. But on submit, the param value is just the file name, no StringIO or anything else, just a String with Filename.
Form:
<%= form_tag(controller: 'search', action: 'confirm_new_search', method: 'post', multipart: true) do %>
[....]
<div class="custom-file field" id="inc_form">
<%= file_field :post, :file_inc_sellerslist, class: "custom-file-input" %>
<label class="custom-file-label" for="file_inc_sellerslist">
<%= t('dashboard.new_search.extra_search_options_entries.choose_file') %>
</label>
</div>
[....]
What is wrong there?
Your form_tag()
syntax is incorrect. form_tag
takes two hashes as arguments: one for the url, one for the html attributes.
form_tag(url_for_options = {}, options = {}, &block)
Starts a form tag that points the action to a url configured with url_for_options just like ActionController::Base#url_for. The method for the form defaults to POST.
Options
:multipart - If set to true, the enctype is set to “multipart/form-data”.
:method - The method to use when submitting the form, usually either “get” or “post”. If “patch”, “put”, “delete”, or another verb is used, a hidden input with name _method is added to simulate the verb over post.
:authenticity_token - Authenticity token to use in the form. Use only if you need to pass custom authenticity token string, or to not add authenticity_token field at all (by passing false). Remote forms may omit the embedded authenticity token by setting config.action_view.embed_authenticity_token_in_remote_forms = false. This is helpful when you're fragment-caching the form. Remote forms get the authenticity token from the meta tag, so embedding is unnecessary unless you support browsers without JavaScript.
:remote - If set to true, will allow the Unobtrusive JavaScript drivers to control the submit behavior. By default this behavior is an ajax submit.
:enforce_utf8 - If set to false, a hidden input with name utf8 is not output.
Any other key creates standard HTML attributes for the tag.
http://api.rubyonrails.org/v5.1/classes/ActionView/Helpers/FormTagHelper.html#method-i-form_tag
The following works for me:
<%= form_tag({controller: 'search', action: 'confirm_new_search'},
method: 'post',
multipart: true) do %>
Here is an example of what happens with your form_tag() call:
def go(x={}, y={})
p x
p y
end
go(a: 1, b:2, c:3)
--output:
{:a=>1, :b=>2, :c=>3}
{}
As a result, all the key/value pairs you specified for form_for()
are gathered into a hash and assigned to the parameter variable url_for_options
. The consequence of that is that your form_tag() isn't setting the html option multipart
to true. If you look at the source for your html, you will see:
<form action="/search/confirm_new_search?method=post&multipart=true"
accept-charset="UTF-8"
method="post">
If you compare that html to your form_tag()
call:
form_tag(controller: 'search',
action: 'confirm_new_search',
method: 'post',
multipart: true)
it's apparent that the last two key/value pairs get added to the query string in the url. That behavior doesn't seem to be documented anywhere, but the rule seems to be: for any key that url_for()
doesn't recognize, the key and the corresponding value get added to the query string. And, key/value pairs in the query string have nothing to do with html attributes for the <form>
tag.