I'm trying to produce a PDF report with Prawn, I can get it to do a report on a show action easily enough by passing the single ID but I want to produce one with every record in it. Like a standard rails scaffold index page. Using rails it would look like this:
<% #customer.each do |customer| %>
<%= customer.id %>
<%= customer.name %>
<%end%>
Easy!
But I'm not sure how to do this with Prawn..
Something like:
def index
#customer = Customer.all
respond_to do |format|
format.html
Prawn::Document.generate("customer_list.pdf") do |pdf|
pdf.text "#{#customer.id} "
pdf.text "#{#customer.name} "
end
end
end
Which clearly isn't right.
Any ideas? Thank you.
It's easy to do with Prawn, Gemfile => gem 'prawn', bundle
lets say you have Customer model:
customers_controller.rb
def show
#customer = Customer.find(params[:id])
respond_to do |format|
format.html
format.pdf do
pdf = CustomerPdf.new(#customer)
send_data pdf.render, filename: "customer_#{id}.pdf",
type: "application/pdf",
disposition: "inline"
end
end
end
then just create pdfs folder under the apps directory, and create file customer_pdf.rb
class CustomerPdf< Prawn::Document
def initialize(customer)
super()
#customer = customer
text "Id\##{#customer.id}"
text "Name\##{#customer.name}"
end
end
show.html.erb
<div class="pdf_link">
<%= link_to "E-version", customer_path(#customer, :format => "pdf") %>
</div>
EDIT:
and don't forget to include pdf to config/initializers/mime_types.rb
Mime::Type.register "application/pdf", :pdf
I think the good solution of your problem is custom renderer. The best approach was described by Jose Valim (!Rails core developer) in his book. The beginning of the first chapter is available for free here. This chapter is really what you need.
This how I do it:
class CustomerPdf< Prawn::Document
def initialize(customer)
super(page_size: "A4", page_layout: :portrait)
#customers = customer
bullet_list
end
def bullet_list
#customers.each do |customer|
text "•#{customer.id}- #{customer.name} ", style: :bold
move_down 5
end
end
end
Related
I have a rails application in which a user can click a link on a page and a little popup opens up with some HTML on it. I'd like to put another link next to it called 'Download as PDF' and when someone clicks this link, I'd like to dynamically generate a PDF from the HTML and allow the user to download the generated PDF onto their system. I've seen a few pages on stackoverflow which talk about using pdfkit to generate pdf from html but nothing about dynamically generating the pdf and then making it available to download. Please help!
The best way to do this is by using gem prawn
Here is youtube of how to upload it to your ruby on rails website https://www.youtube.com/watch?v=BW5zwqj37Lo&t=233s
https://github.com/prawnpdf/prawn
Here is example of how to add gem prawn
gem 'prawn', '~> 1.2.1'
gem 'prawn-table', '~> 0.1.0’
Mime::Type.register "application/pdf", :pdf
def index
#users = User.order("id DESC").all
respond_to do |format|
format.html
format.pdf do
pdf = Prawn::Document.new
pdf.text “hello
send_data pdf.render, filename: 'member.pdf', type: 'application/pdf', disposition: "inline"
end
end
end
<%= link_to 'PDF File', members_path(format: 'pdf') %>
def index
#users = User.order("id DESC").all
respond_to do |format|
format.html
format.pdf do
pdf = MemberPdf.new(#users)
send_data pdf.render, filename: 'member.pdf', type: 'application/pdf', disposition: "inline"
end
end
end
pdfs folder
member_pdf.rb
class MemberPdf < Prawn::Document
def initialize(users)
super(top_margin: 170)
#users=User.order("id DESC").all
user_id
end
def user_id
move_down 20
table user_id_row do
row(0).font_style = :bold
columns(1..3).align = :right
self.row_colors = ["DDDDDD","FFFFFF"]
self.header = true
end
end
def user_id_row
[["id","First","Middle","LastName","Email","Address","Address2","City","PostalCode","phone","Status","Child","Intrest"]] +
#users.map do |user|
[user.id,user.first_name,user.middle_name,user.last_name,user.email,user.street_address,user.street_address2,user.city,user.postal_code,user.phone_number,user.status,user.child,user.interest]
end
end
end
I'm super new to rails. Been learning a few weeks now. Please excuse my idiocy. I cannot get my file I've selected to upload.
I'm using Rails 4.0.0.
I am working on my first application, and I started by following the rails guide for the blog application. I took that and ran with it and am creating something different (bug tracking system) just trying to learn to ropes.
So, I've got my form:
<%= form_for #post do |f| %>
and I've added in my file_field. The display part in from the view looks and works good as far as selecting a file goes.
<%= f.label :attachment %>
<%= f.file_field :attachment %>
I've pulled this from the rails 4 guides FYI. So my controller looks like this:
class PostsController < ApplicationController
def new
#post = Post.new
end
def create
#post = Post.new(params[:post].permit(:title, :text, :user, :screen))
if #post.save
redirect_to posts_path
else
render 'new'
end
end
def show
#post = Post.find(params[:id])
end
def index
#posts = Post.all
end
def edit
#post = Post.find(params[:id])
end
def update
#post = Post.find(params[:id])
if #post.update(params[:post].permit(:title, :text, :user, :screen))
redirect_to posts_path
else
render 'edit'
end
end
def destroy
#post = Post.find(params[:id])
#post.destroy
redirect_to posts_path
end
def upload
uploaded_io = params[:post][:attachment]
File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'w') do |file|
file.write(uploaded_io.read)
end
end
private
def post_params
params.require(:post).permit(:title, :text, :user, :screen, :attachment)
end
end
The new piece in here is upload. Everything else is working fine with writing/reading from the database and displaying. When the view is displayed I make text entries, attached a file and hit submit. Everything writes to the database and shows up on index, but the file I've attempted to attached does not get written to ~/bugs/public/uploads/
Thanks in advance for the help.
I think the problem might be that the :attachment attribute is not a permitted parameter in the "create" or "update" action.
Edit: The way I do simple file uploads is with the Paperclip gem - this railscast explains it well. It's really easy to use.
There's also this answer that might answer the question.
Also, the standard way to use strong parameters is defining permitted params in a private method and calling that method in the controller action (so you don't have to repeat yourself). That might be the cause of the error.
Example:
def create
#post = Post.new(post_params)
...
end
Hope that helps.
I had the same problem,
solution :-
delete the "def upload" and give the code inside "def create" itself
> def create
>
> uploaded_io = params[:post][:attachment]
> File.open(Rails.root.join('public', 'uploads', uploaded_io.original_filename), 'w') do |file|
> file.write(uploaded_io.read)
> end
>
> #post = Post.new(params[:post].permit(:title, :text, :user, :screen))
>
> if #post.save
> redirect_to posts_path
> else
> render 'new'
> end
> end
Make sure that the 'uploads' directory exists in 'public'.
You can handle this automatically by adding this line before the file operation:
Dir.mkdir 'public/uploads' unless File.directory? 'public/uploads'
I'm doin some simple app,i't gonna be some kind of translation app,so i have a search option and adding translations option.I have a problem with my search.When I click on search without any word there,it's shows me a list of translations.i would like to have a flash error there,like a i have it,when i look for a word which is not in database.
my model
class Translation < ActiveRecord::Base
attr_accessible :text_english, :text_polish
validates_presence_of :text_english, :text_polish
validates :text_polish, :text_english, :uniqueness => true
def self.search(search)
if search
where("text_english LIKE ? OR text_polish LIKE ?", "%#{search.strip}%", "%#{search.strip}%")
else
scooped
end
end
end
in my controller
# GET /translations/search
def search
#translations = Translation.search(params[:search])
if !#translations.empty?
respond_to do |format|
format.html
end
else
flash[:error] = "NO TRANSLATIONS"
redirect_to new_translation_url
end
end
end
and my search form in index
<h1>Words</h1>
<%= form_tag search_translations_path, method: :get do %>
<div class="field">
<%= text_field_tag :search, params[:search] %>
<button type="submit" class="btn">Search</button>
<% end %>
thanx for any help.
You have several options, one that is fairly simple would be to add a couple of lines to your controller to account for no params[:search]
# GET /translations/search
def search
if params[:search].blank?
flash[:error] = "A WORD TO TRANSLATE IS REQUIRED"
redirect_to new_translation_url
else
#translations = Translation.search(params[:search])
if !#translations.empty?
respond_to do |format|
format.html
end
else
flash[:error] = "NO TRANSLATIONS"
redirect_to new_translation_url
end
end
end
The important thing to remember is to not allow any path in your code that could redirect or render twice. Hence the if params[:search].blank? .. else
I need to render my #manufacturers array to pdf, but do it only via click on some link in view...
Now i have such code
def index
#manufacturers = Manufacturer.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #manufacturers }
format.pdf { render :layout => false }
end
end
I see a lot of examples in web, but i didn't found clear and actual example... Just how simple do in a4 pdf table with my array #manufacturers ?
In addition to prawn, use the prawnto rails plugin to help with rendering the PDF as a template.
See https://github.com/prior/prawnto for the plugin and http://railscasts.com/episodes/153-pdfs-with-prawn for how to use it.
[Note: the Report gem currently only generates on letter-size paper, patch for A4 would be welcome!]
You can use the Report gem, which generates PDF using Prawn but also XLSX and CSV.
# a fake Manufacturer class - you probably have an ActiveRecord model
Manufacturer = Struct.new(:name, :gsa)
require 'report'
class ManufacturerReport < Report
table 'Manufacturers' do
head do
row 'Manufacturer report'
end
body do
rows :manufacturers
column 'Name', :name
column 'GSA?', :gsa
end
end
# you would want this so that you can pass in an array
# attr_reader :manufacturers
# def initialize(manufacturers)
# #manufacturers = manufacturers
# end
def manufacturers
[
Manufacturer.new('Ford', true),
Manufacturer.new('Fischer', false),
Manufacturer.new('Tesla', nil),
]
end
end
When you call report.pdf.path, a PDF is generating in the tmp directory:
report = ManufacturerReport.new
puts report.pdf.path #=> /tmp/185051406_Report__Pdf.pdf
puts report.xlsx.path #=> /tmp/185050541_Report__Xlsx.xlsx
You can do it in your controller like:
#manufacturers = Manufacturer.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #manufacturers }
format.pdf do
report = ManufacturerReport.new(#manufacturers) # using the commented-out code
send_file report.pdf.path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'ManufacturersReport.pdf'
# tmp files are periodically cleaned up by the operating system, but if you want to be extra clean you can call
# report.cleanup
# but this may remove the tmp files before apache/nginx/etc. finishes delivering the file
end
end
End result:
PDF
XLSX
Note that the XLSX has an autofilter added for you automatically.
I need to supply data from my Ruby on Rails database to a jquery grid plugin. At the moment, I'm doing it like this:
#notes = current_user.notes.all
respond_to do |format|
format.xml { render :xml => #notes }
end
But I only want to display certain fields in the grid, so I need to change the code to only send specified fields from the model. What is the easiest way to do this? Thanks for reading.
you can use XML Builder.
Taken from: http://danengle.us/2009/05/generating-custom-xml-for-your-rails-app/
respond_to do |format|
format.html # index.html.erb
format.xml # index.xml.builder
end
# index.xml builder contents
xml.instruct!
xml.posts do
#posts.each do |post|
xml.post do
xml.title post.title
xml.body post.body
xml.published_at post.published_at
xml.comments do
post.comments.each do |comment|
xml.comment do
xml.body comment.body
end
end
end
end
end
end
Another possibility is to override to_xml in your notes model as posted in the comments of the linked site above.