Active admin CSV export custom query scoped - ruby-on-rails

Am using active admin Export CSV option. Its returning all the values related to the particular table.
I want the reports only for a particular month.
Can anyone help?

you can write own csv exporter
collection_action :download_report, :method => :get do
users = User.where('created_at >= ?', Date.today - 1.month)
csv = CSV.generate( encoding: 'Windows-1251' ) do |csv|
# add headers
csv < [ #Some header ]
# add data
users.each do |user|
csv << [ user.created_at ]
end
end
# send file to user
send_data csv.encode('Windows-1251'), type: 'text/csv; charset=windows-1251; header=present', disposition: "attachment; filename=report.csv"
end
action_item only: :index do
link_to('csv report'), params.merge(:action => :download_report))
end
index :download_links => false do
# off standard download link
end
this is just example for you. Your code can be another

for generation csv file use this code where you want
# generate csv file of photo
def self.generate_csv
header = []
csv_fname = "#{CSV_FILE_PATH}/images.csv"
options = {headers: :first_row}
photo_columns = column_names - ["id", "updated_at"]
photo_columns.map{|col| col == "created_at" ? header << "ScrapeDate" : header << col.classify}
CSV.open(csv_fname, "w", options ) do |csv|
csv << header if File.exist?(csv_fname) && File.size(csv_fname) == 0
find_each(batch_size: 5000) do |photo|
csv << photo.attributes.values_at(*photo_columns)
end
end
end
in above code which column you don't want subtract that cols from actual cols, for example column_names - ["id", "updated_at"] here column_names return actual cols array and which cols we don't need we subtract them.

Related

How to refresh page after send_data in rails 6

Hello devs i'm generating a csv in my controllers but everytime the user clicks on download, it has to refresh manually, how can i avoid this?
#archivo_csv = CSV.generate(:encoding => 'windows-1252') do |csv|
csv << ["indicator","count"]
#indicator[1..#indicator.size].each_with_index do |indicator, i|
csv << ["#{indicator[0]}", indicator[1]]
indicator[2].each do |date|
csv << [" #{date[0]}", date[1]]
end
indicator[3].each do |status|
csv << [" #{status[0]}", status[1]]
end
end
send_data #archivo_csv, :filename => "Indicadores Generales.csv"
end

Using Model.where with self.id or similar when exporting to .CSV

I am trying to export data to CSV based on the current case_main "show" page the export button is on. I believe I need something similar to the following, but I can't get any permutation of it to work. Any attempt at referencing self.id or :id results in an error or nil.
Billedtime.where(case_main_id: self.id).each do |time|
Using Billedtime.all.each do |time| lets the code run, but it obviously grabs everything instead of only billedtimes for the current case_main.
case_main has two one-to-manys, billedtimes and lineitems. I am trying to combine billedtimes + lineitems for a particular case_main into a single .CSV export.
Here is the code:
Model:
def self.to_csv
desired_columns = ["Client Code",
"Case Name" ,
"Date",
"Description",
"Hours",
"Charge",
]
CSV.generate(headers: true) do |csv|
# Header columns
csv << desired_columns
# Data columns
Billedtime.where(case_main_id: self.id).each do |time|
csv <<
[
time.case_main.client.client_code,
time.case_main.case_name,
time.billedtime_date,
time.billedtime_description,
time.billedtime_hours,
time.billedtime_total
]
end
Lineitem.where(case_main_id: self.id).each do |line|
csv <<
[
line.case_main.client.client_code,
line.case_main.case_name,
line.lineitem_date.to_date,
line.lineitem_description,
' ',
line.lineitem_total
]
end
end
end
Controller:
def show
#case_mains = CaseMain.where(:id => #case_main.id).limit(5)
respond_to do |format|
format.html
format.csv { send_data #case_mains.to_csv, filename: "case-#{Date.today}.csv"}
end
end
View:
<%= link_to "Export Billed Items", case_main_path(format: "csv") %>
Thanks!
The issue is that your model doesn't poses an id attribute, so self.id doesn't do the job. Instead you want to grab the current scope using all and iterate through the collection using each or find_each. To prevent an 1+N query I've also added the needed includes call.
def self.to_csv
CSV.generate(headers: true) do |csv|
csv << [
"Client Code",
"Case Name",
"Date",
"Description",
"Hours",
"Charge"
]
all.includes(:client, :billedtimes, :lineitems).find_each do |case_main|
case_main.billedtimes.each do |billedtime|
csv << [
case_main.client.client_code,
case_main.case_name,
billedtime.billedtime_date,
billedtime.billedtime_description,
billedtime.billedtime_hours,
billedtime.billedtime_total
]
end
case_main.lineitems.each do |lineitem|
csv << [
case_main.client.client_code,
case_main.case_name,
lineitem.lineitem_date.to_date,
lineitem.lineitem_description,
' ',
line.lineitem_total
]
end
end
end
end
You might think, I don't want to export all records. However all (without receiver) operates on the current scope, so when you use it in the context CaseMain.where(id: #case_main.id).limit(5).to_csv you will grab the collection CaseMain.where(id: #case_main.id).limit(5).all.

How do I add a custom column to my CSV.generate endpoint in Rails app?

I followed this example but I'm having issues with a nil value showing up in each row (in between the original values and the additional value I'm adding.
Here's my controller endpoint:
def daily_grocery_carts_overview_export
#data = DailyRetailerShop.all.order("start_date ASC")
respond_to do |format|
format.html { redirect_to root_path }
format.csv { send_data #data.to_csv, filename: "DailyGroceryCarts-#{Time.now.strftime("%Y%m%d%H%M%S")}.csv" }
end
end
Here's my model:
class DailyRetailerShop < ActiveRecord::Base
def self.to_csv
# generate site abbreviations & name to add to CSV file
site_abbreviations = {}
Partner.all.each do |p|
site_abbreviations[p[:site_abbreviation]] = p[:name]
end
CSV.generate do |csv|
# remove certain columns
export_columns = column_names - %w(id site_abbreviation created_at updated_at)
# add custom column header
headers = export_columns << 'Website'
# add to csv file
csv << headers
all.each do |item|
row = item.attributes.values_at(*export_columns).insert(-1, site_abbreviations[item.site_abbreviation])
csv << row
end
end
end
end
When I download the CSV file and open it up I see a blank value followed by the custom value I appended in each row. If I read the downloaded CSV file, here's what I see in the first few rows:
data = CSV.read("downloaded_file.csv")
puts data[0..3]
=> [["start_date", "grocery_retailer", "retailer_shops", "Website"], ["2019-10-15", "walmart", "25", nil, "Website1"], ["2019-10-15", "walmart", "24", nil, "Website2"], ["2019-10-15", "instacart", "23", nil, "Website3"]]
Notice there is a nil value for each row (not in the headers). If I exclude my custom header name and then append values as I did above those nil values (blanks when I open the file) are no longer there.
So, it appears the custom header creating a nil value for each row. How do I get rid of that?
I never found out why those nil values are being included in each row but I figured out how to restrict them from showing up. Here's how I modified the function within my model:
class DailyRetailerShop < ActiveRecord::Base
def self.to_csv
# generate site abbreviations & name to add to CSV file
site_abbreviations = {}
Partner.all.each do |p|
site_abbreviations[p[:site_abbreviation]] = p[:name]
end
CSV.generate do |csv|
# remove certain columns
export_columns = column_names - %w(id site_abbreviation created_at updated_at)
# add custom column header
headers = export_columns << 'Website'
# add to csv file
csv << headers
all.each do |item|
# exclude the last item before inserting site name (custom header)
row = item.attributes.values_at(*export_columns)[0..-2].insert(-1, site_abbreviations[item.site_abbreviation])
csv << row
end
end
end
end
Hope this helps someone in the future!

Is there any optimized way to export CSV of more than 100K record using Rails?

I have 200k locations in my database. So I want to export all the locations into CSV format. While doing this it is taking too much time to download. What is the best way to optimize code in rails?
In controller:
def index
all_locations = Location.all
respond_to do |format|
format.csv { send_data all_locations.to_csv, filename: "locations-#{Date.today}.csv" }
end
end
In model
def self.to_csv
attributes = %w{id city address}
CSV.generate(headers: true) do |csv|
csv << ['Id', 'City', 'Address']
all.each do |location|
csv << attributes.map{ |attr| location.send(attr) }
end
end
end
I ran your code with some adjustments with my own data. I made the following changes, and using benchmarking I came to a 7x increase.
Your model:
def self.to_csv
attributes = %w{id city address}
CSV.generate(headers: true) do |csv|
csv << ['Id', 'City', 'Address']
all.pluck(attributes).each { |data| csv << data }
end
end
By using pluck you only get the data you want, and then you push all that data into the csv array.
if you are using Postgresql then you can use this in application_record.rb
def self.to_csv_copy(attrs="*", header=[])
rc = connection.raw_connection
rv = header.empty? ? [] : ["#{header.join(',')}\n"]
sql = self.all.select(attrs).to_sql
rc.copy_data("copy (#{sql}) to stdout with csv") do
# rubocop:disable AssignmentInCondition
while line = rc.get_copy_data
rv << line
end
end
rv.join
end
and then do
Location.to_csv_copy(%w{id city address}, ['Id', 'City', 'Address'])
It is even faster than the above solution.

ArgumentError on CSV output

i'm getting the following error when trying to generate a CSV:
ArgumentError in ProductsController#schedulecsv
wrong number of arguments (0 for 1)
My Products controller is set up as follows:
def schedulecsv
products = Product.find(:all)
filename ="schedule_#{Date.today.strftime('%d%b%y')}"
csv_data = CSV.generate do |csv|
csv << Product.csv_header
products.each do |p|
csv << p.to_csv
end
end
send_data csv_data,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=#{filename}.csv"
end
Does anyone have any pointers here? Driving me bonkers!
Thanks!
From source of csv.rb place in /usr/lib/ruby/(version of your ruby gem)/csv.rb (on my machine)
Here is source code of CSV class's generate method
def CSV.generate(path, fs = nil, rs = nil, &block)
open_writer(path, 'w', fs, rs, &block)
end
generate method require filename as parameter.it will make file with given name,but You are calling CSV.generate filename was missed
so you have to passed name of file in generate call!
filename ="schedule_#{Date.today.strftime('%d%b%y')}"
CSV.generate filename do |csv|
csv << Product.csv_header
products.each do |p|
csv << p.to_csv
end
end

Resources