views:

150

answers:

1

I'd like to be able to read an XML file uploaded by the user (less than 100kb), but not have to first save that file to the database. I don't need that file past the current action (its contents get parsed and added to the database; however, parsing the file is not the problem). Since local files can be read with:

File.read("export.opml")

I thought about just creating a file_field for :uploaded_file, then trying to read it with

File.read(params[:uploaded_file])

but all that does is throw a TypeError (can't convert HashWithIndifferentAccess into String). I really have tried a lot of various things (including reading from the /tmp directory as well), but could get none of them to work.

I hope the brevity of my question doesn't mask the effort I've given to try to solve this on my own, but I didn't want to pollute this question with a hundred ways of how NOT to get it done. Big thanks to anyone who chimes in.

Here is my view: <% form_for(:uploaded_file, @feed, :url => {:action=>'parse'}, :html=> {:multipart=>true}) do |f| %>

<%= f.label :uploaded_file, 'Upload your file.' %>
<%= f.file_field :uploaded_file %>

<% end %>

I set up a custom action (upload) which handles the file_field upload, which after submission, is passed off to another custom action (parse) for processing. Could this be a part of my problem?

+3  A: 

You are very close. Check the class type of params[:uploaded_file], it should typically be either a StringIO or a Tempfile object -- both of which already act as files, and can be read using their respective read method(s).

Just to be sure (the class type of params[:uploaded_file] may vary depending on whether you are using Mongrel, Passenger, Webrick etc.) you can do a slightly more exhaustive attempt:

# Note: use form validation to ensure that
#  params[:uploaded_file] is not null

file_data = params[:uploaded_file]
if file_data.respond_to?(:read)
  xml_contents = file_data.read
elsif file_data.respond_to?(:path)
  xml_contents = File.read(file_data.path)
else
  logger.error "Bad file_data: #{file_data.class.name}: #{file_data.inspect}"
end

If, in your case, it turns out that params[:uploaded_file] is a hash, make sure that you have not mistakingly flipped the object_name and method parameters when invoking file_field in your view, or that your server is not giving you a hash with keys like :content_type etc. (in which case please comment on this post with the Bad file_data ... output from development.log/production.log.)

vladr
Hi Vlad! Thank you for your response.I wasn't exactly sure how to use your code. When I parse, do I call file_data or xml_contents somehow. Like I was just settingxml = File.read(params[:upfile])then I parse(xml)So, I wasn't sure, but not one to stop there, I tried a few different things. I tried using both Webrick and Thin to see if the results were the same... they were. When using File.read(params[:upfile]), I get a "can't convert HashWithIndifferentAccess into String"Could it be how upfile is begin passed in? "uploaded_file"=>{"uploaded_file"=>#<File:C:/Use...
GoodGets
When I try to use the path xml = File.read(params[:upfile].path)I get an undefined method 'path'Could there be something wrong with my "view"? I've edited my question above to include it.
GoodGets
I've been playing around with my View. I'm now using: <% form_for :feed, :url => { :controller => 'feeds', :action => 'parse' } do |f| %> and when I now submit the uploaded file, I get a TypeError "can't convert nil into String" So, I guess something isn't getting passed in correctly.
GoodGets
Back when you say you were seeing `"uploaded_file"=>{"uploaded_file"=>#<File:C:/Use...`, your file was actually in `params[:uploaded_file][:uploaded_file]` which makes me believe you set both `object_name` and `method` to `upload_file` in your view -- back then. With the change to `<% form_for :feed ...>` your controller probably needs to check `params[:feed][:uploaded_file].read`
vladr
Using my current view in my previous comment, and using xml = params[:feed][:uploaded_file].read, I get an undefined method error "read". However, using xml = File.read(params[:feed][:upfile]), I still get an error, but it's an Errno::ENOENT error "No such file or directory". This makes me think that I'm at least on the right track now. Either way, I'm very appreciative of your help Vlad, and feel like I'm close to getting this to work properly.
GoodGets
Holy shit!! You did it!!I went back to my old view, the one in my question, and then used xml = params[:uploaded_file][:uploaded_file].read, and it works!! I couldn't be more thankful. You the man Vlad, thanks.
GoodGets