3

In my view file submit.html.erb, I decided to use the <form> tag straightforwardly, instead of the form helpers included with rails. Here is the view file:

<form action = "/winter" method="post">
<input type="file" name="doc">
<p> Upload your question. </p>
<input type = "submit">
 <input name="authenticity_token" type="hidden" 
      value="....">
</form>

Submitting this form invokes a post request on /winters with parameters

{"doc"=>"1.docx", "authenticity_token"=>"...."}

While I expected the doc parameter to be the file 1.docx I uploaded, the doc parameter continues to be the string original_filename of file 1.docx.

My routes.rb file has the code

post "/winter" => "paper#submit"

while inside the submit method of paper_controller is the code:

File.write("Papers/rain.docx", params[:doc].read)
redirect_to "/paper"

And correspondingly, when I submit the aforementioned form, I go the /winters url and get the error

undefined method 'read' for "1.docx":String

So why is the doc parameter set as the filename rather than the file itself? This is in contrary to the docs, I suppose: [http://guides.rubyonrails.org/form_helpers.html#what-gets-uploaded]

One more point, probably relevant here, is that, there in the doc's first paragraph it says:

Depending on the size of the uploaded file it may in fact be a StringIO or an instance of File backed by a temporary file.

So, is it saying that sometimes the params[:doc] might be a file instance, other times it might be a string? How to deal with such random behavior?

And, one more thing, what if I tried get request instead of put request? get has to put the params right after the url, as a query string, right? So should then params[:doc] be always a string? I tried using get, and was sent to the url

http://localhost:3000/winter?doc=1.docx

(I wasn't using the authenticity token params' hidden input then). And of course, the same

undefined method 'read' for "1.docx":String

error occurred.

Tony Marshle
  • 129
  • 1
  • 2
  • 10

1 Answers1

2

You have to use multipart/formdata encoding for file transfers to work. This is true for any web framework.

I would suggest you just use the form helpers as it will add the correct authenticity token:

<%= form_tag("/winter", multipart: true) do %>
  <%= file_field_tag 'doc' %>
  # ...
<% end %>

And, one more thing, what if I tried get request instead of put request? get has to put the params right after the url, as a query string, right? So should then params[:doc] be always a string? I tried using get, and was sent to the url

You cannot upload files in a GET request. They must be included in the request body of a POST/PATCH/PUT request with multipart/formdata encoding.

Files are binary - the query string which is used to pass data in GET requests is just a string containing formdata key/value pairs. Thus to pass a file in a GET request you would need to base64 encode it which inflates the file size by ~30%. Many browsers also limit the length of URIs as do some web servers to prevent DOS attacks which makes it a really bad idea.

max
  • 96,212
  • 14
  • 104
  • 165
  • [https://www.w3schools.com/tags/att_form_enctype.asp] says "The enctype attribute can be used only if method="post" " and `application/x-www-form-urlencoded` is the default value for `enctype` attribute. So whenever I use input `type="file"` I must use `enctype=multipart/form-data`, right? But the file upload examples in w3schools almost never used `enctype` on file upload examples. So why they did not include the mandatory `enctype=multipart/form-data` line, when the server side processing would break down without it? I mean, the server needs a proper file, not a filename string. – Tony Marshle Nov 24 '17 at 11:42
  • And as previously said W3Schools is clickbait trash which unfortunately has a very high rank on google. Use [MDN](https://developer.mozilla.org/en-US/) if you want a proper reference. – max Nov 24 '17 at 11:44