So I have a Rails application that upon user submission should generate some kind of a .tex file based on the user input, compile it into a pdf, and deliver the pdf. Through process of elimination, I am pretty positive that everything is working except for one line; the one where pdflatex is called.
Here's the vital snippet of code:
(If it matters, its located in the Questions controller under the generate action, which is called after the form sends the relevant information. Though this may not be the best way, I'm pretty certain its not the cause of the error)
texHeader = 'app\assets\tex\QuestionsFront.txt'
texOut = 'app\assets\tex\Questions.tex'
#copy latex header to new file
FileUtils.cp(texHeader, texOut)
File.open(texOut, 'a+') do |fout|
fout.write("\n")
# a loop writes some more code to fout (its quite lengthy)
fout.write("\\end{enumerate}\n")
fout.write("\\end{document}")
#The problem line:
puts `pdflatex app/assets/tex/Questions.tex --output-directory=app/assets/tex`
end
filename = 'Questions.pdf'
filelocation = "app\\assets\\tex\\" + filename
File.open(filelocation, 'r') do |file|
send_file file, :filename => filename, :type => "application/pdf", :disposition => "attachment"
end
end
Here's my reasoning: It generates the .tex file correctly, and given a pre-created Questions.pdf file it sends it just fine. When the command in the puts is copied to the terminal, it runs without a hitch (the file begins with \nonstopmode so no worries about small errors). But for some reason, when I run the above script, not even a log file is created with an error.
What am I overlooking? Any ideas? Any way of seeing what output the puts line is creating?
Thanks so much in advance!
Figured out my own problem. The error is pretty interesting. You'll see I'm calling
puts `pdflatex app/assets/tex/Questions.tex --output-directory=app/assets/tex`
within the block
File.open(texOut, 'a+') do |fout|
where just a few lines prior
texOut = 'app\assets\tex\Questions.tex'
Basically, I'm trying to get latex to compile a document while the file is still open. So long as I'm in the File.open block, the file is open, and its automatically closed upon the end of the block.
Cutting and pasting the line of code down below the end of the block made it work just like I wanted. However, for the sake of clarity and the rare case where someone else has this problem, its actually better to open a separate system shell, navigate to the directory where the latex document is and do the compiling there. So, my updated code looks like:
fout.write("\\end{document}")
end
system 'runlatex.bat'
where that batch file is as follows:
cd app/assets/tex
pdflatex Questions.tex
That way any additional files in the tex directory are found, the log file is created there, etc.
Reason why I never got a log file? The pdflatex never executed - the OS stopped it with a permissions error before it ever ran.
Hope this helps!
Backticks (and %x{}) provide the same parsing context as a double quoted string. That means that the usual backslashed escape sequences are interpreted inside backticks; in particular, \t is a tab so this:
puts `pdflatex app\assets\tex\Questions.tex --output-directory=app\assets\tex`
will end up with two tabs in and that breaks everything. You can start escaping your backslashes (I think you'll need two or three backslashes to get one down to the shell) or switch to normal slashes (which Windows usually accepts in paths):
puts `pdflatex app/assets/tex/Questions.tex --output-directory=app/assets/tex`
Alternatively, you could switch to open3 to avoid the escaping and quoting issues and also get better error handling capabilities.
Related
I discovered from here that if you have a script you want to run in the rails console, you sometimes have to copy paste it line by line (copy pasting it all at once doesn't always work)
This is very tedious for lengthy scripts
Is there a work around or faster way?
Example - this will not copy paste from text editor to console:
class Article
def initialize(title, link, paragraphs)
#title = title
#link = link
#paragraphs = paragraphs
end
attr_reader :title
attr_reader :link
attr_reader :paragraphs
end
Edit
The above snipped does copy paste right into the rails console. But when I grab the same text from sublime text 3, it errors after the second line, with:
Display all 522 possibilities? (y or n)..
The Answer
I worked out why. My script (in sublime text) used tabs as indents. The rails console only accepts spaces as indents. That's an hour of my life I won't get back. I hope this saves someone else some time.
This issue (pasting multi-line code into irb on the console, on a Mac, using iTerm) bugged me for a long time and finally found the solution.
In my case the issue was with iTerm. It turns out iTerm by default pastes the content at a speed that is too fast for readline, the library that irb uses to read input.
The solution was to do Edit > Paste Special > Paste Slower, twice.
See here for a similar case: https://gitlab.com/gnachman/iterm2/issues/3607
SOLUTION
Open the rails console with this option:
rails console -- --nomultiline
You can paste many lines of code without problem then.
EXPLANATION
The problem here is that IRB wants to write a letter at a time. You can disable this behaviour by giving up the ability to move the cursor up and down when you write and edit a block of code before closing it.
Source:
https://tosbourn.com/speed-up-pasting-text-into-rails-console/
I can't comment because of reputation, so i add an answer about a 'tips' that can save some of your time.
In most of the text editor / IDE used to write code you can choose to replace the tabulation by an amount of space. It's a good thing to do so to avoid the tabulation characters in files raising some errors like yours ;)
https://www.sublimetext.com/docs/3/indentation.html
For me replacing tabs to spaces wasn't enough, maybe because the content i was trying to paste was so large. What worked for me was removing all unneeded spaces, replacing newlines with semicolons, and replacing do...end blocks with one line curly bracket blocks. Basically getting everything into as few lines as possible.
Trying to replicate this simple Lua example (using the improved code in the second post), I encountered the following strange issue:
I copied the code verbatim, but happened to call the first file "table.lua" (instead of "funcs.lua").
The second file was called "main.lua" as in the example.
In my case, whatever I tried, I invariably got the popular error message "attempt to call field 'myfunc' (a nil value)" (as if the require statement had been ignored; but path etc. were all in order).
After two hours of trying and hunting for info, I more or less on a hunch renamed the first file from "table.lua" to "tabble.lua", and then everything promptly worked as expected. Renaming to e.g. "tables.lua" will also work.
Being very new to Lua, I'd still like to understand what exactly went wrong. Initially I thought the reason might be that "table" is a reserved Lua word, but all references I checked do not list it as such.
So what is going on here?
I am using LuaForWindows v5.1.4-46 with the included SciTE editor/IDE (v.1.75).
Thanks for all hints.
The standard libraries math, io, string, …, and table are pre-defined (and pre-loaded) in the Lua interpreter. Because require caches modules by name, saying require "table" will return the standard table library instead of loading your own table module from a file.
A good way to solve the problem is to create a folder and put your library files in there. If the folder is called mylib, then require "mylib.table" will work and load the file.
Alternatively, if you just need to load the file once and do not need the features of require (searching the file in a number of directories, caching loaded libraries), you can use loadfile: Change require "table" to loadfile "./table.lua" () (where ./table.lua should be the full (relative is fine) path to the file.)
I'm trying to use Kivy as a GUI for my python app, which needs to read a file from the filesystem.
However, in some cases the kivy filechooser read wrong path or nothing causing an IndexError while I'm trying to set the read path for a text of a textfield.
I use the default example for reading files learned from http://kivy.org/docs/api-kivy.uix.filechooser.html
The relevant part of my app is in this function, where an exception handling is added as a not a good approach to handle this :)
def load(self, path, filename):
'''
this will load the file and dismiss the dialog
'''
print "Loading file..."
print "filename:",filename
print "path:",path
try:
self.selected_file = filename[0]
self.file_text_input.text = self.selected_file
self.dismiss_popup()
except IndexError as ie:
print "Something made a boo-boo...try again"+str(ie)
self.dismiss_popup()
self.show_popup("ERROR","Somehow I couldn't load the file:\nCheck the permissions or move it to other place")
self.show_popup() is just a helper function, which shows a popup with the set function params.
The basic error is that filename[0] will throw an IndexError since it does not read the correct path.
I'm using Linux with python2.7, and somethimes when I select a file in my home folder, the filename variable stores nothing, while path variable stores misteriously a random folder, for instance, /media, /opt, etc.
Did anyone meet this issue?
I found out why it was handled uncorrectly.
All the failures are caused by Kivy's
FileChooserListView
, which enables to click on folders and files via a list, but it also makes it possible to have a littel '>' sign at the beginning of every list element, which are directories.
I realized that when I used these '>' signs, then I get wrong path, but if I always clicks on the directories' list elements then everything works fine.
However, that little '>' cannot be disabled (for now), so the best and fastest alternate solution is using
FileChooserIconView
instead!
Now everything is good :)
I'm sending the file file.txt from my Rails controller using send_file, and then delete the folder containing it.
send_file("#{Rails.root}/public/folder/file.txt")
FileUtils.remove_dir "#{Rails.root}/public/folder", true
When I did this, file.txt was sent and deleted. However, folder was not deleted. But if I remove the send_file line, then folder will be deleted.
How do I make it delete folder?
EDIT: Interestingly, I found that inside folder there is a hidden file called .__afs2B0C, probably preventing the deletion. I have no idea how this file is created! The file stays for only around 15 minutes before disappearing.
EDIT2: I've tried inspecting the content of the temp file with vi, but it's unreadable gibberish. When I removed only the send_file line, the folder was correctly deleted. When I removed only the FileUtils.remove_dir line, the folder contains no temp file.
Are you sure the send_file is not still sending the file when you are removing the dir, it may be asynchronous if it uses X-SendFile? That would cause an error when trying to remove the dir.
So you should probably be queuing this delete action, or doing it with a sweeper later, rather than trying to do it straight after sending the file to streaming.
I'm not completely clear on which file you are sending, so it would be useful to include an actual example of file path, and file type, and how it is created in your question.
Possible help with debugging:
Log in and monitor the folder while you perform the following actions:
Write out a very large file (> 60MB say), and check there is no invisible file created during your file creation process - I'm not clear on which file you are actually sending
Set up a large file transfer on a slow connection, and watch for the creation and possibly growing of this file (it might be related to compressing the file served on the fly for example).
Given that sendfile may still be sending (for large files) via the web server (x-send-file is now default) when you try to delete, I'd try looking into delayed solutions.
Possible solutions:
Use send_data rather than send_file (if files are small)
Schedule the deletion of the folder for later with something like delayed_job
Set up a sweeper which removes the folders at the end of each day
Not sure why that hidden file is there, it could be an offshoot of X-send-file or even of wget (partial progress or something).
Ideally, you should use Tempfile to do things like this. The code is based of you're comment about what you are doing. Also, I am using two gems one for downloading and another for zipping.
This way, you don't need to make a folder at all, just a zip file directly. All the content files of the zip will be deleted on their own. After downloading the zip just delete it. Here also I should mention that you could run into a glitch somewhere, since the send_file will hand over the transfer to the webserver, and as such you don't the rails process to delete the file while it is still being served. So even with this, and it working well on localhost, I would strongly advise using a custom scheduled background garbage collector in production.
require 'open-uri'
require 'zip/zip'
zip_path = "#{Rails.root}/public/test.zip"
urls_to_fetch = ['abc.com', 'xyz.com']
Zip::ZipFile.open(zip_path, Zip::ZipFile::CREATE) do |zipfile|
urls_to_fetch.each_with_index do |url, index|
# intialize new temp file
file = Tempfile.new(index.to_s)
# fetch the file using open-uri or wget and save it as a tmpfile
open(url, 'rb') do |read_file|
file.write(read_file.read)
end
end
# add the temp file to the list of files to zip
zipfile.add(File.basename(file), file.path)
end
# send the zipfile for download
send_file zip_path
# delete the zipfile
FileUtils.rm zip_path
However, this should not be mandatory. If you are doing things without Tempfiles, please check the rights that the rails runner has on the target directory.
The FileUtils documentation has details regarding local security vulnerabilities when trying to delete files / folders.
See here... works for me
file = File.open(Rails.root.join('public', 'uploads', filename), "rb")
contents = file.read
file.close
File.delete(filepath) if File.exist?(filepath)
send_data(contents, :filename => filename)
maybe you could try this solution:
http://info.michael-simons.eu/2008/01/21/using-rubyzip-to-create-zip-files-on-the-fly/
it is so simple but dangerous. Use shell command to achieve it . Put it after send_file in Controller
system ("rm -rf public/folder")
I am trying to upload a file in rails (using paperclip), and I want to process some of the file data before letting paperclip send it off to s3 storage. In my controller, I just grab the file parameter (which does give me a file) and then I try to read the lines into an array
csv_file = params[:activity][:data]
array = IO.readlines(csv_file.path)
The problem is, I'm only getting the last line of the file. I tried using .rewind, but still get just the last line.
I dislike readlines and I always use regular expressions. Try this.
End of line - \n
Handy block structure to ensure that the file handle is closed:
File.open(csv_file.path) do |f|
a = f.readlines
process a...
end
Reading a whole file into memory might not be a good idea depending on the size of the files.