Ruby on Rails PDF Stamper / iText - ruby-on-rails

I have done a lot of searching and cannot find a solution for getting PDF-stamper to work in my rails application. From the tutorials it appears that I write a method in the model? I wrote a simple app with two fields: nameLast and nameFirst. All I want to do is write these to a PDF I have that contains fields for user info. Two field happen to be FirstName and LastName so perfect time to use PDF-stamper right? I just want to take user data from the rails application and have then be able to push a button and generate a PDF. Here is the method I have in my model.
def savePDF
pdf = PDF::Stamper.new("sample.pdf")
pdf.text :nameFirst, "Jason"
pdf.text :nameLast, "Yates"
pdf.save_as "my_output.pdf"
end
That was clearly taken from a tutorial that I must not properly understand. I can actually get this working in java pretty easy, but I don't want to use jRuby. I am using rjb which is working fine. I just don't think I properly understand what needs to happen to get this working. Any help is greatly appreciated!

I'm the author of the pdf-stamper gem.
The save_as method saves the created PDF to the filesystem. If you are building a Rails application, I don't think that is what you want.
I'm guessing from your question you want to send a "stamped" PDF back to the browser. If that is the case, you should call to_s on the created PDF and then pass the output of that to Rails send_data method.
In your controller(not the model) you'll want to add some code like this.
def send
pdf = PDF::Stamper.new("sample.pdf")
pdf.text :nameFirst, "Jason"
pdf.text :nameLast, "Yates"
send_data(pdf.to_s, :filename => "output.pdf", :type => "application/pdf",:disposition => "inline")
end
The problem here really is the documentation for the pdf-stamper gem. The feature you wanted was there just undocumented, hence your confusion. I'll have to fix that.

i was doing the same with use of xfdf as a source data for fields, the following code worked for me, maybe it will be helpful to you aswell:
pdfreader = Rjb::import('com.itextpdf.text.pdf.PdfReader')
pdfstamper = Rjb::import('com.itextpdf.text.pdf.PdfStamper')
pdffields = Rjb::import('com.itextpdf.text.pdf.AcroFields')
xfdfreader = Rjb::import('com.itextpdf.text.pdf.XfdfReader')
pdf = pdfreader.new("#{Rails.root}/public/out/temp/form1.pdf", nil)
xfdf = xfdfreader.new(f)
stamp = pdfstamper.new(pdf, filestream.new("/tmp/text#{i}.pdf"))
pdffields = stamp.getAcroFields()
pdffields.setFields(xfdf)
stamp.close

Related

How to convert PDF to Excel or CSV in Rails 4

I have searched a lot. I have no choice unless asking this here. Do you guys know an online convertor which has API or Gem/s that can convert PDF to Excel or CSV file?
I am not sure if here is the best place to ask this either.
My application is in Rails 4.2.
PDF file has contains a header and a big table with about 10 columns.
More info:
User upload the PDF via a form then I need to grab the PDF parse it to CSV and read the content. I tried to read the content with PDF Reader Gem however the result wasn't really promising.
I have used: freepdfconvert.com/pdf-excel Unfortunately then don't supply API. (I have contacted them)
Sample PDF
This piece of code convert the PDF into the text which is handy.
Gem: pdf-reader
def self.parse
reader = PDF::Reader.new("pdf_uploaded_by_user.pdf")
reader.pages.each do |page|
puts page.text
end
end
Now if you check the sample attached PDF you will see some fields might be empty which it means I simply can't split the text line with space and put it in an array as I won't be able to map the array to the correct fields.
Thank you.
Ok, After lots of research I couldn't find an API or even a proper software that does it. Here how I did it.
I first extract the Table out of the PDF into the Table with this API pdftables. It is cheap.
Then I convert the HTML table to CSV.
(This is not ideal but it works)
Here is the code:
require 'httmultiparty'
class PageTextReceiver
include HTTMultiParty
base_uri 'http://localhost:3000'
def run
response = PageTextReceiver.post('https://pdftables.com/api?key=myapikey', :query => { f: File.new("/path/to/pdf/uploaded_pdf.pdf", "r") })
File.open('/path/to/save/as/html/response.html', 'w') do |f|
f.puts response
end
end
def convert
f = File.open("/path/to/saved/html/response.html")
doc = Nokogiri::HTML(f)
csv = CSV.open("path/to/csv/t.csv", 'w',{:col_sep => ",", :quote_char => '\'', :force_quotes => true})
doc.xpath('//table/tr').each do |row|
tarray = []
row.xpath('td').each do |cell|
tarray << cell.text
end
csv << tarray
end
csv.close
end
end
Now Run it like this:
#> page = PageTextReceiver.new
#> page.run
#> page.convert
It is not refactored. Just proof of concept. You need to consider performance.
I might use the gem Sidekiq to run it in background and move the result to the main thread.
Check Tabula-Extractor project and also check how it is used in projects like NYPD Moving Summonses Parser and CompStat criminal complaints parser.
Ryan Bates covers csv exports in his rails casts > http://railscasts.com/episodes/362-exporting-csv-and-excel this might give you some pointers.
Edit: as you now mention you need the raw data from an uploaded PDF, you could use JavaScript to read the PDF file and the populate the data into Ryan Bates' export method. Reading PDF's was covered excellently in the following question:
extract text from pdf in Javascript
I would imagine the flow would be something like:
PDF new action
user uploads PDF
PDF show action
PDF is displayed
JavaScript reads PDF
JavaScript populates Ryan's raw data
Raw data is exported with PDF data included

How to export data from model to excel file on rubyonrails

I'm trying to export data from my models to an excel spreadsheet. I have seen 3 ways
Using the spreadsheet gem which I didn't understand how to use it,
the examples I saw was writing to a local file but I'm looking to
generate a file every time user clicks on a link.
Creating a method called export, and running the query there, then
making a export.xls file in my view, and that file creating the
table I want to be exported to the excel file, but this approach
don't allow me to create multiple sheets.
Followed this tutorial, http://oldwiki.rubyonrails.org/rails/pages/HowToExportToExcel,
but here doesn't show how to put the link in the view, looks to me that I'm missing something in the routes, I can give github so you can take a look at my code if needed.
My choice is to just manualy generate CSV file. Like:
File.new("data.csv", "w+") do |f|
#my_data.each do |data|
f << [data.title, data.body, ...].join(", ") + "\n"
end
end
CSV file can be opened with excel or any other spreadsheet soft.
I'm using writeexcel in my most recent Rails project. A fast and simple to use way to export excel files directly - no CSV!
To use it directly in your views you have to register writeexcel as a template handler - this is excalty what my gist does. Then create a new template like export.xls.writeexcel, insert your code and you're good to go.
Plugging my own gem here, but you might have a look at https://github.com/randym/acts_as_xlsx
It gives you a bit more than writeexcel or spreadsheet in terms of localization, graphs, tables and formatting from the axlsx gem.
It also integrated with active record scoping and method chains.
Blogpost with detailed usage examples:
http://axlsx.blogspot.com/
http://axlsx.blogspot.jp/2011/12/using-actsasxlsx-to-generate-excel-data.html
http://axlsx.blogspot.jp/2011/12/axlsx-making-excel-reports-with-ruby-on.html
On Github: https://github.com/randym/axlsx
On Rubygems: https://rubygems.org/gems/axlsx
On Rubytookbox: https://www.ruby-toolbox.com/projects/axlsx
Basically it involves setting up a responder in your controller
format.xlsx {
xlsx_package = Post.to_xlsx
begin
temp = Tempfile.new("posts.xlsx")
xlsx_package.serialize temp.path
send_file temp.path, :filename => "posts.xlsx", :type => "application/xlsx"
ensure
temp.close
temp.unlink
end
}
and the following on your model
class Post < ActiveRecord::Base
acts_as_xlsx
The two blog posts above give a fairly clear walk-through.

Built-in way to convert xml to an ActiveRecord Object in Rails 3?

In Rails 3, is there a way to produce an ActiveRecord object from xml in a controller without writing code yourself to explicitly parse it? Say for example, could a controller receive xml like
<user>
<first_name>Bob</first_name>
<last_name>Smith</last_name>
</user>
and have it produce a proper User object similar to User.new(params[:user])? This is for an api.
Yes, you can do it like this:
#user = User.new
#user.from_xml(xml_data)
Update
On overriding you can do something like this:
#user.rb
def from_xml(xml_data)
book = Book.new
book.from_xml(extract_xml_from(xml_data))
self.books << book
super(xml_data)
save
book.save
end
Please note that the most important line in the overriding is the super(xml_data) which will take care on calling the original from_xml(xml_data) of the ActiveRecord model.
So you can customize the rest as needed, but this line is neede if you want to get the original functionality as well.
Let me know if something is not clear.
I've created a gem, xml_active that might help you with this without having to write a lot of code. You can check it out at https://rubygems.org/gems/xml_active.
To get it to create one object with associations just do the following:
book = Book.one_from_xml xml_data
You can also get xml_active to create many objects from xml along with associations. There are more features but probably not in the scope of this answer. You can check them out on the home page for the gem.
UPDATE
xml_active has now been officially retired and development is now focused on data_active (see https://github.com/michael-harrison/data_active) which has the functionality of xml_active but in future releases I will be working to support other formats

nokogiri replace

I'm parsing an HTML document and trying to replace the image src. It seems to do what I want when I attempt it in the console however in my model it doesn't seem to save it. Now, I'm not sure if what I'm doing is wrong with the way to save in Rails (i'm trying to update the content field and replacing external images with local ones) or if it's using nokogiri, but it's not saving the result using the set_attribute method
It does the rest of it perfectly.
before_save :replace_zemanta_images
def replace_zemanta_images
doc = Nokogiri::HTML(content)
unless doc.css('div.zemanta-img').blank?
doc.css('div.zemanta-img img').each do |img|
io = open(URI.parse(img[:src]))
if photos.find_by_data_remote_url(img[:src]).blank?
photo = photos.build(:data => io, :data_remote_url => img[:src])
img.set_attribute('src', photo.data.url(:original)) #doesn't work!
end
end
end
end
I am assuming that content is an attribute on your model.
When you are doing img.set_attribute you are updating the attribute in the Nokogiri::XML::Element object but this doesn't update the text of content.
At the end of your method you will need to add something like:
self.content = doc.to_s
JackChance mentioned to use Nokogiri::HTTP::DocumentFragment.parse(content) here for a fragment (if you don't want DOCTYPE/HTML/BODY tags), I didn't have any luck with that since my original HTML was a snippet instead of the whole document.
I ended up using something like this:
html = Nokogiri::HTML.fragment
to initially convert the HTML string snippet to a Nokogiri object without the unnecessary tags.
Then once we use img.set_attribute, we can convert back html.to_s

Liquid Templates Not Parsing!

Im trying to use Liquid Template Language in my Rails Application, i've watched Ryan Bates' video over at rails cast, i pretty much follow the instructions but it just doesnt seem to work!
When I try something like
#template = Liquid::Template.parse("Hi {{name}}")
#template.render('name' => 'toby')
I get
hi toby
but when i try something like
category = Category.first
#template = Liquid::Template.parse("Hi {{category.name}}")
#template.render('category' => category)
I don't get the desired result, I get only
hi ""
Can someone please help me out with this?
When the value is not a hash, you need to tell liquid which methods it can read from the passed object.
This documentation page show you how to instruct ActiveRecord.
The quickest way is to use the liquid_methods macro.

Resources