In my application, the user must upload a text document, the contents of which are then parsed by the receiving controller action. I've gotten the document to upload successfully, but I'm having trouble reading its contents.
There are several threads on this issue. I've tried more or less everything recommended on these threads, and I'm still unable to resolve the problem.
Here is my code:
file_data = params[:file]
contents = ""
if file_data.respond_to?(:read)
contents = file_data.read
else
if file_data.respond_to?(:path)
File.open(file_data, 'r').each_line do |line|
elts = line.split
#
#
end
end
end
So here are my problems:
file_data doesn't 'respond_to?' either :read or :path. According to some other threads on the topic, if the uploaded file is less than a certain size, it's interpreted as a string and will respond to :read. Otherwise, it should respond to :path. But in my code, it responds to neither.
If I try to take out the if statements and straight away attempt File.open(file_data, 'r'), I get an error saying that the file wasn't found.
Can someone please help me find out what's wrong?
PS, I'm really sorry that this is a redundant question, but I found the other threads unhelpful.
Are you actually storing the file? Because if you are not, of course it can't be found.
First, find out what you're actually getting for file_data by adding debug output of file_data.inspect. It maybe something you don't expect, especially if form isn't set up correctly (i.e. :multipart => true).
Rails should enclose uploaded file in special object providing uniform interface, so that something as simple as this should work:
file_data.read.each_line do |line|
elts = line.split
#
#
end
Related
I'm trying to access http://www.orimi.com/pdf-test.pdf to test if "PDF Test File" exists.
This is my code:
it 'pdf test' do
visit 'http://www.orimi.com/pdf-test.pdf'
puts page.title
sleep 5
convert_pdf_to_page
expect(page).to have_content 'PDF Test File'
end
def convert_pdf_to_page
temp_pdf = Tempfile.new('pdf')
temp_pdf << page.source.force_encoding('UTF-8')
reader = PDF::Reader.new(temp_pdf)
pdf_text = reader.pages.map(&:text)
temp_pdf.close
page.driver.response.instance_variable_set('#body', pdf_text)
end
But I got:
PDF::Reader::MalformedPDFError: PDF does not contain EOF marker
I searched and I found that the problem can be the PDF file. I checked the temp_pdf variable and there is just HTML with a empty body.
Is there something wrong in my code?
PDF is a tricky format, and different readers react differently to unexpected content in the PDF files. Some would crash, others would make assumptions to not crash.
I'd guess this is what happens here. When you open the file in the browser/pdf reader it works, but PDF::Reader can't handle whatever is not-standard there.
Try using different gem, Origami seems to have good opinions. I tried it with your file, and it seems to work:
> require 'origami'
> pdf = Origami::PDF.read '/tmp/pdf-test.pdf'
> pdf.grep(/Not existing/).any?
=> false
> pdf.grep(/PDF Test File/).any?
=> true
For reference (how I came up with this answer):
I googled the PDF::Reader::MalformedPDFError: PDF does not contain EOF marker and found this thread, which suggests that it's a more common problem with "working" PDFs. One of the last messages suggests the Origami, which (after checking) seems to be able to handle the PDF in question.
I have a decent amount of knowledge about Ruby code, but I do have an issue with my current project. I use Gosu to make 2D games (and once I figure out how, simple 3D games), so I need a resolution.
And this is where my question comes in, why does Ruby keep giving me an error when seeing if the settings file exists? I've been trying to get it working with the file not existing, which keeps giving me the error, "'initialize': No such file or directory # rb_sysopen - ./settings.set (Errno::ENOENT)" which has been annoying me for the last few days. The file gives no issues and actually works as intended when I leave the file created, but I want it to be where if the file gets deleted off of someone's computer, it rebuilds the file and creates a new one using default values.
Here's the area that it keeps crashing at:
settings = []
settings_file_existance = File.file?("settings.set")
if settings_file_existance == true
File.open("settings.set").readlines.each do |line|
settings.push line
end
else
settings_file = File.open("settings.set")
settings_file.write "800"
settings_file.write "\n"
settings_file.write "600"
settings_file.close
end
I have tried looking for fixes on this site, along with many others, but no one so far has been able to help.
You could try this:
settings = []
if File.file?("settings.set")
settings = File.read("settings.set").split("\n")
else
File.open("settings.set", "w") do |file|
file.write "800\n600"
end
end
As a side note, consider that the above code will set settings only if settings.set file exits, otherwise it will remain in an empty array (i.e. []).
If you wish to avoid that, just define settings with the default values, for example:
settings = [800, 600]
Now if settings.set file doesn't exist, then settings will be [800, 600], otherwise it will be overwritten with the values from settings.set.
To avoid writing 800 and 600 twice, you could use settings variable to get the values to be written in the new file, for example:
file.write(settings.join("\n"))
Putting it all together, your code would look like this:
settings = [800, 600]
if File.file?("settings.set")
settings = File.read("settings.set").split("\n")
else
File.open("settings.set", "w") do |file|
file.write(settings.join("\n"))
end
end
I have an input file and a batch file. When the batch file is executed using the System command,
a corresponding outfile is generated.
Now I want a particular text (position 350 to 357) from that outfile to be displayed on to my lineedit widget
Here is that part of my code:
system("C:/ORG_Class0178.bat")
Now the outfile will be generated
File.open("C:/ORG_Class0178_out.txt", 'r').each do |line|
var = line[350..357]
puts var
# To test whether the file is being read.
#responseLineEdit = Qt::LineEdit.new(self)
#responseLineEdit.setFont Qt::Font.new("Times NEw Roman", 12)
#responseLineEdit.resize 100,20
#responseLineEdit.move 210,395
#responseLineEdit.setText("#{var}")
end
When I do test whether the file is being read using puts statement, I get the exact required output in editor. However, the same text is not being displayed on LineEdit. Suggestions are welcome.
EDIT: A wired observation here. It works fine when I try to read the input file and display it , however it does not work with the output file. The puts statement does give the answer in editor confirming that output file does contain the required text. I am confused over this scenario.
There is nothing wrong with the code fragments shown.
Note that var is a local variable. Are the second and third code fragments in the same context? If they are in the same method, and var is not touched in-between, it will work.
If the fragments belong to different methods of the same class, than an instance variable (#var) will solve the problem.
If all that does not help, use Pry to chase the problem. Follow the link to find the pre-requisites and how to use. Place binding.pry in your code, and your program will stop at that line. Then inspect what your variables are doing.
try 'rb' instead of 'r'
File.open("C:/ORG_Class0178_out.txt", 'rb').each do |line|
var = line[350..357]
puts var
I have a function in my code that takes a string representing the url of an image and creates a File object from that string, to be attached to a Tweet. This seems to work about 90% of the time, but occasionally fails.
require 'open-uri'
attachment_url = "https://s3.amazonaws.com/FirmPlay/photos/images/000/002/443/medium/applying_too_many_jobs_-_daniel.jpg?1448392757"
image = File.new(open(attachment_url))
If I run the above code it returns TypeError: no implicit conversion of StringIO into String. If I change open(attachment_url) to open(attachment_url).read I get ArgumentError: string contains null byte. I also tried stripping out the null bytes from the file like so, but that also made no difference.
image = File.new(open(attachment_url).read.gsub("\u0000", ''))
Now if I try the original code with a different image, such as the one below, it works fine. It returns a File object as expected:
attachment_url = "https://s3.amazonaws.com/FirmPlay/photos/images/000/002/157/medium/mike_4.jpg"
I thought maybe it had something to do with the params in the original url, so I stripped those out, but it made no difference. If I open the images in Chrome they appear to be fine.
I'm not sure what I'm missing here. How can I resolve this issue?
Thanks!
Update
Here is the working code I have in my app:
filename = self.attachment_url.split(/[\/]/)[-1].split('?')[0]
stream = open(self.attachment_url)
image = File.open(filename, 'w+b') do |file|
stream.respond_to?(:read) ? IO.copy_stream(stream, file) : file.write(stream)
open(file)
end
Jordan's answer works except that calling File.new returns an empty File object, whereas File.open returns a File object containing the image data from stream.
The reason you're getting TypeError: no implicit conversion of StringIO into String is that open sometimes returns a String object and sometimes returns a StringIO object, which is unfortunate and confusing. Which it does depends on the size of the file. See this answer for more information: open-uri returning ASCII-8BIT from webpage encoded in iso-8859 (Although I don't recommend using the ensure-encoding gem mentioned therein, since it hasn't been updated since 2010 and Ruby has had significant encoding-related changes since then.)
The reason you're getting ArgumentError: string contains null byte is that you're trying to pass the image data as the first argument to File.new:
image = File.new(open(attachment_url))
The first argument of File.new should be a filename, and null bytes aren't allowed in filenames on most systems. Try this instead:
image_data = open(attachment_url)
filename = 'some-filename.jpg'
File.new(filename, 'wb') do |file|
if image_data.respond_to?(:read)
IO.copy_stream(image_data, file)
else
file.write(image_data)
end
end
The above opens the file (creating it if it doesn't exist; the b in 'wb' tells Ruby that you're going to write binary data), then writes the data from image_data to it using IO.copy_stream if it's a StreamIO object or File#write otherwise, then closes the file again.
If you use Paperclip, they have a method to copy to disk.
def raw_image_data
attachment.copy_to_local_file.read
end
change attachment to what ever variable you used of course.
So, I wrote a simple Ruby class, and put it in my rails /lib directory. This class has the following method:
def Image.make_specific_image(paths, newfilename)
puts "making specific image"
#new_image = File.open(newfilename, "w")
puts #new_image.inspect
##blank.each(">") do |line|
puts line + "~~~~~"
#new_image.puts line
if line =~ /<g/
paths.each do |p|
puts "adding a path"
puts p
#new_image.puts p
end
end
end
end
Which creates a new file, and copies a hardcoded string (##blank) to this file, adding custom content at a certain location (after a g tag is found).
If I run this code from ruby, everything is just peachy.
HOWEVER, if I run this code from rails, the file gets CREATED, but is then empty. I've inspected each line of the code: nothing I'm trying to write to the file is nil, but the file is empty nonetheless.
I'm really stumped here. Is it a permissions thing? If so, why on EARTH would Rails have the permissions necessary to MAKE a file, but then not WRITE to the file it made?
Does File I/O somehow work differently in rails?
Specifically, I have a model method that calls:
Image.make_specific_image(paths, creature.id.to_s + ".svg")
which succesfully makes a file of the type "47.svg" that is empty.
Have you tried calling close on the file after you're done writing it? (You could also use the block-based File.open syntax, which will automatically close once the block is complete). I'm guessing the problem is that the writes aren't getting flushed to disk.
So.
Apparently File I/0 DOES work in Rails...just very, very slowly. In Ruby, as soon as I go to look at the file, it's there, it works, everything is spiffy.
Before, after seeing blank files from Rails, I would get frustrated, then delete the file, and change some code and try again (so as not to be full of spam, since each file is genearted on creature creation, so I would soon end up with a lot of files like "47.svg" and "48.svg", etc.
....So. I took my lunch break, came back to see if I could tell if the permissions of the rails generated file were different from the ruby generated file...and noticed that the RAILS file is no longer blank.
Seems to take about five minutes for rails to finally write to the file, even AFTER it claims it's done processing that whole call. Ruby takes a few seconds. Not really sure WHY they are so different, but at least now I know it's not a permissions thing.
Edit: Actually, on some files take so long, others are instant...