4

I am referring to the stackoverflow post https://stackoverflow.com/a/2521135/2607331

to understand how to read files.

View -

<%= form_tag  ('/greetings/hello') do %>
  <label for="file">File to Upload</label> <%= file_field_tag "file" %>
  <div><%= submit_tag 'Process' %></div>
<% end %>

Routes -

Rails.application.routes.draw do
  post 'greetings/hello'

controller -

class GreetingsController < ApplicationController
def hello
  @filename = params[:file]

  if @filename.respond_to?(:read)
    @lines = file_data.read
  elsif @filename.respond_to?(:path)
    @lines = File.read(file_data.path)
  else
    logger.error "Bad file_data: #{@filename.class.name}: #    
    {@filename.inspect}"
  end
  render "hello"
 end
end

As per the post, the params[:file] would be a tempfile or StringIO object, however in my case it is string. Not sure what is going wrong. Below is the logger output.

Started POST "/greetings/hello" for 183.83.51.8 at 2016-05-03 03:45:40 +0000
Cannot render console from 183.83.51.8! Allowed networks: 127.0.0.1, ::1, 127.0.0.0/127.255.255.255
Processing by GreetingsController#hello as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"0r0Ny6rqlv9Gts1PBh+J4Dk7B+9WPea3HK1cgR/dWTLFrkXW+eggX+tie4wFs+F4lHM5RGpAHXL6EO3sKjd0sw==", "file"=>"sitcomquery.txt", "commit"=>"Process"}
Bad file_data: String: "sitcomquery.txt"
  Rendered greetings/hello.html.erb within layouts/application (5.6ms)
Completed 500 Internal Server Error in 97ms (ActiveRecord: 0.0ms)

EDIT

Changed index.html.erb to include multipart -

<%= form_tag '/greetings/hello' ,multipart: true do %>
  <label for="file">File to Upload</label> <%= file_field_tag "file" %>
  <div><%= submit_tag 'Process' %></div>
<% end %>

In controller, I am able to read it with -

 tempfl = params[:file]
 @lines = tempfl.read

However, @lines is a big string. I need to read it in such a way that @lines is array of lines. However readlines is not a method of ActionDispatch::Http::UploadedFile object. Do i need to save the file and perform readlines, or is there anyway I can read each line without saving file.

Community
  • 1
  • 1
Tushar Saurabh
  • 687
  • 2
  • 13
  • 27

3 Answers3

4

You should add multipart to your form just like the following

<%= form_tag '/greetings/hello', multipart: true do %>
Lymuel
  • 574
  • 3
  • 10
2
class GreetingsController < ApplicationController
  def hello
    @filename = params[:file]

    if @filename.respond_to?(:read)
      @lines = file_data.read
    elsif @filename.respond_to?(:path)
      @lines = File.read(file_data.path)
    else
      logger.error "Bad file_data: #{@filename.class.name}: #    
                {@filename.inspect}"
    end
    render "hello"
  end
end

In this code @filename contains a string and you have checked string contains method read or not by boolean function respond_to? and it always gonna return false because string do not have method read. there are lots of option to check file below is one of them.

file = File.file?(params[:file])

if file
  @lines = File.read(params[:file])
else
 "your message"
end

OR if you want to read params file as IO object you need to add multipart in form

<%= form_for(<object>, url: <path>, method: :post, remote: :true, html: {
  multipart: true, }) do |f| %>
    <input type="file" name="file_batch_upload" />
<% end %>

For more details

https://stackoverflow.com/a/36765124/5715918

Community
  • 1
  • 1
rohin-arka
  • 779
  • 4
  • 10
  • Shadow you can refer to this answer to improve your answer http://stackoverflow.com/questions/36764566/rails-cant-import-data-from-csv-file/36765124#36765124 – Shiva May 03 '16 at 05:26
  • @Shadow I have included multipart: true, I am able to see file and able to read it using file.read. However, the output is one big string. My requirement is to get each lines in array (similar to readlines). Do I need to to save file and perform readlines. Can i achieve it without saving the file. Please see the edit in original questions. – Tushar Saurabh May 04 '16 at 05:32
  • Hi @TusharSaurabh for getting each lines in array. This should work `lines = File.foreach(params[:file]).to_a` – rohin-arka May 04 '16 at 05:50
  • @Shadow it is not working. The error I get is "no implicit conversion of ActionDispatch::Http::UploadedFile into String". – Tushar Saurabh May 05 '16 at 04:06
1

The issue was to read each lines of uploaded file and spit it out line by line. Normal readlines or each_line method doesnt work as the Uploaded file is of class "UploadedFile" and doesnt support IO methods. The solution can be found in another stackoverflow post -

is there a rails method to loop through each line of uploaded file? "each_line" is an IO method but it's not working

Thanks!!

Community
  • 1
  • 1
Tushar Saurabh
  • 687
  • 2
  • 13
  • 27