Calling def in Ruby for exporting CSV - ruby-on-rails

I currently have some code which iv used to export a table from the data I have
require 'fastercsv'
def dump_csv
#users = User.find(:all, :order => "lastname ASC")
#outfile = "members_" + Time.now.strftime("%m-%d-%Y") + ".csv"
csv_data = FasterCSV.generate do |csv|
csv << [
"Last Name",
"First Name",
"Username",
"Email",
"Company",
"Phone",
"Fax",
"Address",
"City",
"State",
"Zip Code"
]
#users.each do |user|
csv << [
user.lastname,
user.firstname,
user.username,
user.email,
user.company,
user.phone,
user.fax,
user.address + " " + user.cb_addresstwo,
user.city,
user.state,
user.zip
]
end
end
send_data csv_data,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=#{#outfile}"
flash[:notice] = "Export complete!"
end
my question is how do I call it from my view and will this work with will_pagination. I know FasterCVS creates tables using the ActiveRecord so will_paginiation wont be of any use when trying to organize the table.

I don't understand why you are talking about will_paginate...
But if you want to send data or send a file from a controller, you should look at the methods send_data and send_file :
http://api.rubyonrails.org/classes/ActionController/Streaming.html

Thanks for your help. I saw your link and came up with this:
#lists = Project.find(:all, :order=> (params[:sort] + ' ' + params[:direction]), :conditions => ["name || description LIKE ?", "%#{params[:selection]}%"])
csv_string = FasterCSV.generate do |csv|
csv << ["Status","Name","Summary","Description","Creator","Comment","Contact Information","Created Date","Updated Date"]
#lists.each do |project|
csv << [project.status, project.name, project.summary, project.description, project.creator, project.statusreason, project.contactinfo, project.created_at, project.updated_at]
end
end
filename = Time.now.strftime("%Y%m%d") + ".csv"
send_data(csv_string,
:type => 'text/csv; charset=utf-8; header=present',
:filename => filename)
end

Related

Using gem axlsx, how would I create multiple workbooks in one program?

Using basic axlsx code, I need to create a workbook, close it and create a new workbook within the same program. The workbooks will have generated names and a variable number will be created. At this point, I can create the sheets I need but, given my requirements, I have duplicate sheet names. In any case, I need to create multiple files.
I am working from the basic github example:
Axlsx::Package.new do |p|
p.workbook.add_worksheet(:name => "Pie Chart") do |sheet|
sheet.add_row ["Simple Pie Chart"]
%w(first second third).each { |label| sheet.add_row [label, rand(24)+1] }
sheet.add_chart(Axlsx::Pie3DChart, :start_at => [0,5], :end_at => [10, 20], :title => "example 3: Pie Chart") do |chart|
chart.add_series :data => sheet["B2:B4"], :labels => sheet["A2:A4"], :colors => ['FF0000', '00FF00', '0000FF']
end
end
p.serialize('simple.xlsx')
end
Running code, simplified, as an example. It uses the to_stream method, but it seems the key is using different packages for each workbook. Using the to_stream method with a block closes the file when its done.
class Unload < ApplicationController
require 'axlsx'
package = Axlsx::Package.new
workbook = package.workbook
puts "Companies"
workbook.add_worksheet(name: "Companies") do |sheet|
sheet.add_row ["Name", "Domain", "Prefix"]
Company.all.each do |a|
sheet.add_row [a.name, a.domain, a.prefix]
end
end
stream = package.to_stream()
File.open('db/unloaded/Joint.xlsx', 'wb') { |f| f.write(stream.read) }
workbook = nil
stream = nil
package = nil
Company.all.each do |c|
puts "Company is: " << c.name
ActsAsTenant.with_tenant(c) do
c.package = Axlsx::Package.new
c.workbook = c.package.workbook
company_name = c.blank? ? "Invalid Company" : c.name
puts "Associates for #{company_name}"
c.workbook.add_worksheet(name: "Associates") do |sheet|
sheet.add_row ["Logon", "Name", "Email", "Cell", "Company"]
Associate.all.each do |a|
sheet.add_row [a.logon, a.name, a.email, a.cell, company_name]
end
end
puts "Serializing for #{company_name}"
stream = c.package.to_stream()
File.open("db/unloaded/#{company_name}.xlsx", 'wb') { |f| f.write(stream.read) }
c.workbook = nil
stream = nil
c.package = nil
end
end
end

how to pass extra parameters in to_csv method

Controller
format.csv { send_data #find_customer.to_csv, :filename => "customer" + ".csv" }
format.xls { send_data #find_customer.to_csv(col_sep: "\t"), filename: 'customer.xls'}
Model
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << ["SHW#", "LeadId", "Fullname", "Address", "City", "State", "Zip", "Phone", "Email", "Created-At"]
all.each do |customer|
csv << [customer.id, customer.leadid, "#{customer.first_name} #{customer.last_name}", customer.customer_address, customer.customer_city, customer.customer_state, customer.customer_zip, customer.customer_phone, customer.email, customer.created_at.strftime("%m/%d/%Y")]
end
end
end
How to pass extra parameters in to_csv method. I want to pass start_date and end_date in to_csv method so How can I ?
Update 1
If I pass
format.xls { send_data #find_customer.to_csv(col_sep: "\t", :start_date => "date"), filename: 'customer.xls'}
Then getting error like : Unknown option start_date
Try this:
format.csv { send_data #find_customer.to_csv({}, '2014-05-08', '2014-05-10'), :filename => "customer" + ".csv" }
model
def self.to_csv(options = {}, start_date = '', end_date = '')
CSV.generate(options) do |csv|
csv << ["SHW#", "LeadId", "Fullname", "Address", "City", "State", "Zip", "Phone", "Email", "Created-At", "Start", "End"]
all.each do |customer|
csv << [customer.id, customer.leadid, "#{customer.first_name} #{customer.last_name}", customer.customer_address, customer.customer_city, customer.customer_state, customer.customer_zip, customer.customer_phone, customer.email, customer.created_at.strftime("%m/%d/%Y"), start_date, end_date]
end
end
end

How do I create one CSV file containing two models with comma gem?

I would like to create one CSV file containing two models with comma gem in my ruby 3.2.8 application. Maybe the answer to the question is trivial, but this is the first time I use this gem. I know how create the file it based on a model, but I don' t know how make matches of two.
I have a views\participants\index with :
<%= link_to 'Download CSV', '/participants.csv' %>
the controller :
def index
#participants = Participant.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #participants }
format.csv { send_data #participants.to_comma }
end
end
participant Model:
require 'comma'
class Participant < ActiveRecord::Base
comma do
id
token
end
end
and field Model:
require 'comma'
class Field < ActiveRecord::Base
comma do
name
value
id_participant
end
end
in the db i have:
Participant1 = ["id" => 1 , "token" => "a"]
Participant2 = ["id" => 2 , "token" => "b"]
Field1= ["id_participant" => 1, "name" => "p1_exams1", "value" =>5]
Field2= ["id_participant" => 1, "name" => "p1_exams2", "value" =>3]
Field3= ["id_participant" => 2, "name" => "p2_exams1", "value" =>2]
Field4= ["id_participant" => 2, "name" => "p2_exams2", "value" =>3]
I would like to have a file like this:
id token
1 a
id_p name value
1 p1_c1_exams1 5
1 p1_c1_exams2 3
id token
2 b
id_p name value
2 p1_c1_exams1 2
2 p1_c1_exams2 3
I tried with this in controller:
def index
#participants = Participant.all
#fields = Field.all
require 'csv'
csv_string = CSV.generate do |csv|
#participants.each do |p|
csv << ["id","token","last_ip_address","start_date","last_transition_date","completion_date","completed","total_time_survey","created_at"]
csv << [ p.id, p.token , p.last_ip_address, p.start_date, p.last_transition_date, p.completion_date, p.completed, p.total_time_survey, p.created_at]
#fields.each do |f|
if String(f.id_participant) == String(p.id)
csv << ["id","name","value","id_participant","id_survey","created_at"]
csv << [f.id,f.name, f.insert_value, f.id_participant, f.id_survey, f.created_at]
end
end
end
end
respond_to do |format|
format.html # index.html.erb
format.json { render json: #participants }
format.csv { send_data csv_string,
:type => "text/csv; charset=iso-8859-1; header=present",
:disposition => "attachment; filename=Database.csv" }
end
end
You can also use the fastercsv for this
i think this will help u what i am understanding that u have has many relationship between Participant and Field regarding this i have write some piece of code u can customize it as ur need
#participants = Participant.all
csv_string = FasterCSV.generate do |csv|
#participants.each do |i|
csv << ["id","token"]
csv << [ i.id, i.token ]
i.fields.each do |j|
csv << ["id_p","name", "value"]
csv << [i.id,j.name, j.value]
end
end
end
send_data csv_string,
:type => "text/csv; charset=iso-8859-1; header=present",
:disposition => "attachment; filename=anyName.csv"

generating email address images or something which can't be easily scraped

I'm looking for a better Text-to-image solution for my Rails project to replace my current method which is generating a png using ImageMagick every time a new record is created or updated.
I want to prevent a mass scraping of data and abuse of email addresses provided. I'm wondering if there is an API to generate the text or use of javascript, or SVG, etc. Anything short of Flash.
I'm looking for a better solution than my current method:
def create_new_email_image
if email_changed?
path_to_images = '/images/emails'
puts "Connecting to AWS..."
config = YAML.load(File.open("#{RAILS_ROOT}/config/s3_credentials.yml"))[RAILS_ENV]
AWS::S3::Base.establish_connection!(
:access_key_id => config['access_key_id'],
:secret_access_key => config['secret_access_key']
)
puts "Finding S3 bucket..."
begin
bucket = AWS::S3::Bucket.find config['bucket_name']
rescue AWS::S3::NoSuchBucket
AWS::S3::Bucket.create config['bucket_name']
bucket = AWS::S3::Bucket.find config['bucket_name']
end
images_path = "#{RAILS_ROOT}/tmp/"
file_name = "#{id}.png"
#file_name = "5056.png"
file_path = images_path + "/"+ file_name
File.delete file_path if File.exists? file_path
img = Magick::Image.new(400, 22) { self.background_color = 'transparent' }
img.format = 'PNG'
text = Magick::Draw.new
text.annotate(img, 0, 0, 1, 0, "#{email}") {
self.gravity = Magick::WestGravity
self.pointsize = 18
self.fill = '#000000'
self.kerning = -1
self.font_weight = Magick::BoldWeight
}
img.write file_path
if AWS::S3::S3Object.exists? file_name, bucket.name + path_to_images
puts "file exists (deleting)"
AWS::S3::S3Object.delete file_name, bucket.name + path_to_images, :force => true
end
AWS::S3::S3Object.store file_name,
File.open(file_path),
bucket.name + path_to_images,
:content_type => 'image/png',
:access => :public_read,
:reload => true
`rm #{file_path}`
end
end
Rails provides a mail_to helper.
mail_to "me#domain.com"
# => me#domain.com
mail_to "me#domain.com", "My email", :encode => "javascript"
# => <script type="text/javascript">eval(decodeURIComponent('%64%6f%63...%27%29%3b'))</script>
mail_to "me#domain.com", "My email", :encode => "hex"
# => My email
mail_to "me#domain.com", nil, :replace_at => "_at_", :replace_dot => "_dot_", :class => "email"
# => me_at_domain_dot_com
mail_to "me#domain.com", "My email", :cc => "ccaddress#domain.com",
:subject => "This is an example email"
# => My email
The :encode => "hex" or :encode => "javascript" options are what you are looking for.
I've had the same problem. Here is my solution:
def text_to_image(text,options={})
return if text.blank?
filename=get_text_file_path(text)
unless File.exists?(filename)
gc = Magick::Draw.new
gc.fill = options[:color] unless options[:color].blank?
gc.pointsize options[:size] unless options[:size].blank?
gc.font=options[:font] unless options[:font].blank?
gc.gravity = Magick::CenterGravity
gc.text(0,0, text)
metrics=gc.get_type_metrics(text)
image = Magick::Image.new(metrics.width, metrics.height){
self.background_color = 'transparent'
}
gc.draw(image)
image.write(filename)
end
end
I use after_save callback to update graphic cache of email attribute.

FasterCSV layout

I need to layout my CSV into columns not rows. So going down the spreadsheet not across. For example:
Header 1, value1.1, value2.1
Header 2, value1.2, value2.2
Header 3, value1.3, value2.3
Does anyone know how to do this? I've been through the documentation and can't find anything about changing the layout to columns.
EDIT:
row_data = [];
csv_string = FasterCSV.generate do |csv|
# header row
row_data << ["id", "Name", "Age"]
# data rows
Playerapplication.find_each do |player|
row_data << [player.id, player.name, player.age]
end
row_data.transpose
csv << row_data
end
# send it to the browser
send_data csv_string,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=players_application.csv"
Simply use Array#transpose on your data before writing to CSV.
If you modify your code like this:
row_data = [];
csv_string = FasterCSV.generate do |csv|
# header row
row_data << ["id", "Name", "Age"]
# data rows
Playerapplication.find_each do |player|
row_data << [player.id, player.name, player.age]
end
row_data.transpose.each do |row|
csv << row
end
end
it works for me.

Resources