Why only first page results get exported to csv? - ruby-on-rails

I am trying to get ALL the filtered results when exporting to CSV.
My to_csv is working fine, and I suspect something to do with my controller.
Search around with kaminari, ransack, but seems like even exporting to csv is rare using ransack.
Any help is much appreciated.
controller.rb
#search = Order.includes(:user, :order_items).ransack(params[:q])
#orders = #search.result.order(created_at: :desc).page(params[:page])
respond_to do
|format|
format.html
format.csv { send_data #orders.to_csv, filename: "orders-#{DateTime.now.strftime("%d%m%Y%H%M")}.csv" }
end
view.html.haml
= link_to 'Download as CSV', a_o_path(request.params.merge(format: 'csv')), { class: 'btn btn-primary', style: 'float: right;' }

You can do this with ransack and kaminari, but you'll need to update your controller just a bit. Here's what you have so far:
format.csv { send_data #orders.to_csv, filename: "orders-#{DateTime.now.strftime("%d%m%Y%H%M")}.csv" }
When your controller gets here, #orders has been filtered by ransack, but it has also been paginated by kaminari. Since you're responding with html in some cases and csv in others, you'll want to do something slightly different when you respond with csv.
Here's what I would try:
#search = Order.includes(:user, :order_items).ransack(params[:q])
#orders = #search.result.order(created_at: :desc)
respond_to do |format|
format.html { #orders = #orders.page(params[:page]) }
format.csv { send_data #orders.to_csv, filename: "orders-#{DateTime.now.strftime("%d%m%Y%H%M")}.csv" }
end
Basically, you only paginate the query when you respond with html. When csv is requested, all of the orders will still be there.

Related

Downloading CSV downloads all files, need it to download specific ones

I'm having a little trouble downloading values to a CSV file. I have two models, downtowns and properties. Downtowns have many properties. Properties each have one downtown. Problem i'm having is that with what i've done i've been able to download all properties, which is cool! But what I'm struggling with is downloading only properties owned by the downtown.
To what I have initially to download all properties I have
In my properties controller:
def index
#properties = Property.all
respond_to do |format|
format.html
format.csv { send_data #properties.to_csv }
end
end
In my properties model
def self.to_csv
attributes = %w(id name owner_first_name created_at)
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |property|
csv << property.attributes.values_at(*attributes)
end
end
end
and then in my view I have.
= link_to "download CSV", downtown_properties_path(:format => :csv), class: "button"
So again this works, but because of my associations the view where i can add my link can only be in downtowns/1/properties which based on my putting the code in the index this actually makes sense
I tried something along the lines of
#download_properties = Property.where(downtown: #downtown_id)
respond_to do |format|
format.html
format.csv { send_data #download_properties.to_csv }
end
However #downtown_id is not defined at this point. So I think the solution is better in the downtown model?
If anyone has any idea looking through this and able to help me out, I would greatly appreciate it!
shouldn't it be:
#download_properties = Property.where(downtown: params[:id])
or
#download_properties = Downtown.find(params[:id]).properties

Index page not rendering but downloads csv

I am working on a rails app which reads the JSON data then creates a CSV from that data. The issue I am facing is the CSV download works perfectly fine but the index page doesn't show.
When I go to localhost:3000 the CSV is downloaded but index.html.erb page is not rendered. Please help me find the issue where I am going wrong.
controller.rb
def index
csv_data = CSV.generate do |csv|
file = JSON.parse(File.open("app/assets/javascripts/data.json").read)
#data = file
new_file = #data.sort_by!{ |m| m["name"] }
new_file.each do |hash|
hash['name'] = (hash.values[2])
hash['city'] = (hash.values[3])
end
end
send_data csv_data, type: :csv
end
routes.rb
root :to => "name#index"
index.html.erb
<h1 align="center">File is downloaded</h1>
if I add the code below in the controller index action then the html is rendered but the download csv stops working.
respond_to do |format|
format.html
format.csv { send_data csv_data, type: :csv }
end
You need to add html format as respond format:
def index
csv_data = ..
respond_to do |format|
format.html
format.csv { send_data csv_data }
end
end
1/ Extract your CSV logic in a private method:
def download_csv
csv_data = CSV.generate do |csv|
file = JSON.parse(File.open("app/assets/javascripts/data.json").read)
#data = file
new_file = #data.sort_by!{ |m| m["name"] }
new_file.each do |hash|
hash['name'] = (hash.values[2])
hash['city'] = (hash.values[3])
end
end
send_data csv_data, type: :csv
end
2/ Call your private method inside before_action:
before_action :download_csv, only: :index
3/ Update your route to set html by default (maybe not necessary):
root :to => "name#index", defaults: { format: 'html' }
Basically calling send_file/send_data from a before action will not halt the request cycle, because it doesn't use render or redirect_to.
I hope it helps.
__Edited answer__
Actually I guess is not a regular comportement to render multiple routes for one action. And I think you should find another way to achieve this. I recommend you the following code (from my first solution):
1/ Add a specific route to download
get '/name/download_csv', to: "name#download_csv"
2/ Add some Jquery in your view
<script>
$(document).ready(function() {
window.location.href = 'name/download_csv.csv';
})
</script>
3/ Remove the private reserved word from your controller
In this way each time you go to your index view you are going to call your download action throughout Jquery.
It's not really "rails way" but it should works.
Let me know if it works.

Rails Exporting CSV ignore blanks

I'm trying to create a simple CSV export in Rails. The export works fine except when deleting/archiving table items. I'm guessing this is because the export is encountering blanks.
This is working:
= link_to transactions_path(format: :csv) do
Except when there is a item missing from the transaction.
Tried this
= link_to transactions_path(format: :csv,skip_blanks: true) do
but I still get a ERR_INVALID_RESPONSE when calling the export
TransactionController:
respond_to :html, :json, :csv
def index
#shops = current_user.shops
respond_with(#shops) do |format|
format.csv do
response.headers['Content-Type'] = 'text/csv'
response.headers['Content-Disposition'] = "attachment; filename=transactions-#{Time.now.strftime('%Y%m%d%H%M')}.csv"
render inline: #shops.to_csv
end
end
end
Any suggestions?
Change to_csv to pass skip_blanks.
#shops.to_csv(skip_blanks: true)
If you want a link to download a CSV file, you should use send_data instead. If you want to display the file in the browser, use render text: #shops.to_csv
http://railscasts.com/episodes/362-exporting-csv-and-excel
respond_to :html, :json, :csv
def index
#shops = current_user.shops
respond_with(#shops) do |format|
format.csv do
send_data #shops.to_csv, type:'text/csv', filename: "transactions-#{Time.now.strftime('%Y%m%d%H%M')}.csv"
end
end
end
Change your link_to back to what you had before.
= link_to transactions_path(format: :csv)
Maybe using send_data:
def index
respond_to do |format|
format.csv { send_data #current_user.shops.to_csv, filename: "transactions-#{Time.now.strftime('%Y%m%d%H%M')}.csv" }
end
end
Also, is the to_csv an instance method?

Why is Rails exporting all rows instead of only filtered results?

I'm running a Rails 4 application and am using the Ransack gem to filter results for employees. I've seen multiple examples of how to limit columns on the exported CSV file, but not on limiting rows. To my understanding, the following code should call the .to_csv method on the filtered employees, but currently all rows are being downloaded. Do I need to pass an array of the IDs of the filtered results to the .to_csv method?
View:
<h3>Download</h3>
<%= link_to "CSV", employees_path(format: "csv") %>
Controller:
def index
#q = Employee.ransack(params[:q])
#q.build_condition
#employees = #q.result(distinct: true)
respond_to do |format|
format.html
format.csv { render text: #employees.to_csv }
end
end
Model:
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |employee|
csv << employee.attributes.values_at(*column_names)
end
end
end
I know this is a bit delayed but this is how I fixed same problem.
Change the link to have params.merge to keep the filtered results.
<%= link_to "CSV", employees_path(params.merge(format: "csv")) %>
I also had to change my format.csv to the following to get it to work:
format.csv { send_data #employees.to_csv, filename: "employees.csv" }
Hope this helps.
In this line you're adding all of the employee models.
all.each do |employee|
Instead you should have something like
def self.to_csv(employees)
..
employees.each do |employee|
..
end
And call this class method like this:
format.csv { render text: Employee.to_csv(#employees) }
(Read more about class methods here)

Ransack export results to CSV

I'm trying to export a list of Ransack (Railscast) results to a CSV file (Railcast). However, it keeps exporting all of the objects, instead of the results returned by the Ransack search. Can anyone tell me where I'm going wrong?
In the Reports controller, I've tried passing both #bookings and #search.result:
def index
#search = current_user.bookings.search(params[:q])
#bookings = #search.result
#search.build_condition
respond_to do |format|
format.html
format.csv { render text: Booking.to_csv(#bookings) }\
end
end
And then the Booking to_csv method:
def self.to_csv list
CSV.generate do |csv|
csv << column_names
list.each do |booking|
csv << booking.attributes.values_at(*column_names)
end
end
end
Yet every time, I get the unfiltered list of current_user.bookings. Why?
To export only the filtered results as csv, you should make sure that the search parameters are included in the url you call to generate the csv.
Hence, if you want to export the results that you see on the html page you should call:
reports_path(params.merge(format: 'csv')
Try this:
def index
session[:q] = params[:q] if params[:q]
#search = current_user.bookings.search(session[:q])
#bookings = #search.result
#search.build_condition
respond_to do |format|
format.html
format.csv { render text: Booking.to_csv(#bookings) }\
end
end

Resources