I am new to ruby on rails and I am having trouble in exporting the data to csv. I have followed the following video:
https://medium.com/coderaga/rails-import-export-csv-data-without-gem-fbf2a36a84f6
I have put require 'csv' in application.rb file also.
My student.rb model has:
def self.to_csv(fields = column_names, options = {})
CSV.generate(options) do |csv|
csv << fields
all.each do |student|
csv << student.attributes.values_at(*fields)
end
end
end
My students_controller has following:
def index
#students=Student.all
puts #students
respond_to do |format|
format.html
format.csv{send_data #students.to_csv(['UIN', 'Name' ,'Section', 'Attempts', 'Score'])}
end
end
I think the all.each statement is empty as when I am doing puts student.attributes.values_at(*fields), there is nothing so that is why there is nothing being written. But I am not sure how can I fix it.
Student Load (0.3ms) SELECT "students".* FROM "students"
#<Student:0x007f9a2386ddb8>
#<Student:0x007f9a2386dc78>
#<Student:0x007f9a2386db38>
CACHE Student Load (0.0ms) SELECT "students".* FROM "students"
Please help
Try
where.each do |student|
puts student #Debug
csv << student.attributes.values_at(*fields)
end
Related
I am trying to export some data to CSV in Rails 4. I have two models: Excursions and Inscriptions. One excursion has many inscriptions and one inscription belongs to one excursion.
I have my nested routes defined this way:
resources :excursions do
resources :inscriptions
get 'exportcsv' => 'excursions#download'
end
So the behavior I am trying to achieve is: when I visit the route /excursions/1/exportcsv, a CSV will be downloaded to my computer and it will contain all the inscriptions with excursion_id = 1 in CSV format.
In my excursion model I have defined self.to_csv:
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
self.inscriptions.each do |inscription|
csv << inscription.attributes.values_at(*column_names)
end
end
end
And my excursion controller's method download:
def download
#excursion = Excursion.find(params[:id])
respond_to do |format|
format.html
format.csv { send_data #excursion.to_csv }
end
end
EDIT: When I go to a route like: /excursions/:id/exportcsv the server is throwing an ActiveRecord::RecordNotFound error. This error is easy to solve, but if I solve the RecordNotFound I get an ActionController::UnknownFormat in this line:
def download
#excursion = Excursion.find(params[:id])
respond_to do |format| ########THIS LINE
format.html
format.csv { send_data #excursion.to_csv }
end
end
What I am doing wrong? Maybe all this approach is not correct...
I would update the routes to the following:
resources :excursions do
get 'download', on: :member, constraints: { format: /(html|csv)/ }
resources :inscriptions
end
Also there is a bug in your model code. You are exporting inscriptions but are using Excursion column_names instead of Inscription column_names. Following is the updated model code.
class Excursion < ActiveRecord::Base
def to_csv(options = {})
CSV.generate(options) do |csv|
inscription_column_names = Inscription.column_names
csv << inscription_column_names
self.inscriptions.each do |inscription|
csv << inscription.attributes.values_at(*inscription_column_names)
end
end
end
Now try to access http://localhost:3000/excursions/:id/download.csv
Replace :id with an existing Excursion records id. If you still encounter ActiveRecord::RecordNotFound error, then the problem could be that you are trying to access an Excursion that doesn't actually exist in the database.
I am trying to generate a CSV output with data from my database. I would like to provide these data to a third party, so I picture I would give to someone a URL (website.com/api_data/cars) and by accessing this URL the person would be able to work with it - I think I want to access the URL and then to see there (in the action) data displayed and separated by , or ;.
But how to do that?
So far, I am trying following approach:
csv_string = CSV.generate do |csv|
cols = ["column one", "column two", "column three"]
csv << cols
csv << ["A", "B", "C"]
#filename = "data-#{Time.now.to_date.to_s}.csv"
end
send_data(csv_string, :type => 'text/csv; charset=utf-8; header=present', :filename => #filename)
This is in the controller generate_data and action csv_cars.
When I run this action (webste.com/generate_data/csv_cars), it will automatically pop up a window to download the file.
But how to write the CSV content to the action? So when I open the URL, I'll see there written the content from the database?
I know this is an old thread but I came across it in my search so in case someone else does the same, here's my answer and what worked for me.
I think bhanu had a good way of going about it but I did change something. Instead of doing #cars within the respond_to, I just called send_data Cars.to_csv since, as Rob stated, it was made as a class method. It worked beautifully for me.
class Car < ActiveRecord::Base
def self.to_csv(make)
attributes = %w{id name price} #customize columns here
cars = Car.where(maker_name: make)
CSV.generate(headers: true) do |csv|
csv << attributes
cars.each do |car|
csv << attributes.map{ |attr| car.send(attr) }
end
end
end
end
And then in the controller
class CarsController < ApplicationController
def index
send_data Cars.to_csv('Chevy'), filename: "cars-#{Date.today}.csv"
end
end
I understand that this will be called when you go to cars/index but you can put that into any method, if statement or anything you want and just have it called whenever you would like from there. You can also have arguments, as I did above with make, and query for certain fields. It was definitely a lot easier than I thought it was going to be. Hope this helped someone.
You need to do something like this.
def csv_cars
headers = ['column one', 'column two', 'column three']
csv_data = CSV.generate(headers: true) do |csv|
csv << headers
csv << ["A", "B", "C"]
end
send_data csv_data, filename: "data-#{Date.today.to_s}.csv", disposition: :attachment
end
define a to_csv method in your model as shown below
class Car < ActiveRecord::Base
def self.to_csv
attributes = %w{id name price} #customize columns here
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |car|
csv << attributes.map{ |attr| car.send(attr) }
end
end
end
end
Later in your controller
class CarsController < ApplicationController
def index
#cars = Car.all
respond_to do |format|
format.html
format.csv { send_data #cars.to_csv, filename: "cars-#{Date.today}.csv" }
end
end
end
I have in my controller a section that generates an array of Song objects. For each song object, I want to output some of it's information to a csv file. I found instructions online and followed them to the best of my ability.
The controller:
def index
#stations = Station.all
#csv crap
#played = []
Station.first.users.each do |u|
u.playlists.where("updated_at > ?", Date.today).each do |p|
#played << p
end
end
#songs = []
if !#played.empty?
#played.each do |pl|
pl.songs.each do |s|
#songs << s
end
end
end
#data = []
#data << "Song"
#data << "Album"
#data << "Artist"
(0...#songs.length).each do |s|
son = #songs[s]
#data << [son.title, Album.find(son.album_id).name, Artist.find(son.artist_id).name]
end
respond_to do |format|
puts "******************\n\n\n\n\n\n\n\n"
puts #songs.inspect
puts "******************\n\n\n\n\n\n\n\n"
format.html
format.csv { send_data #data.to_csv(), filename:"daily_report.csv" }
end
end
The model:
def self.to_csv(options = {})
puts "fuck all"
CSV.generate(options) do |csv|
csv << column_names
options.each do |item|
csv << item.title
csv << item.attributes.values_at(*column_names)
csv << item.attributes.values_at(*column_names)
end
end
end
For some reason, the controller is never using the model to generate the csv, which it should be. I have to extra stuff in the controller to try to make it generate correctly there, but I really want it to generate in the model. Any idea why it never hits the self.to_csv in the model?
Your model's to_csv method isn't being called because you're not calling it - you're calling a to_csv instance method on an array.
You need something along the lines of
ModelClass.to_csv(#songs)
and your to_csv method should be closer to
def self.to_csv(data, options = {})
CSV.generate(options) do |csv|
csv << column_names
data.each do |item|
csv << [item.title]
csv << item.attributes.values_at(*column_names)
csv << item.attributes.values_at(*column_names)
end
end
end
I'm a bit confused about what you're adding to the csv (for example why are the item attributes added twice?) but this should at least produce a csv.
Im doing an export to CSV in Rails everything seems to be ok no errors and the file is being generated, but only the column headers are been exported no other data.
Here is some of the code:
in controller:
#students = Student.where("START_DATE >= ? and END_DATE <= ? and COURSE_NAME like ?", params[:start_date], params[:end_date], params[:course_name]).select('name, course')
(...)
format.csv { send_data #students .to_csv }
in model:
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |valeo|
csv << valeo.attributes.values_at(*column_names)
end
end
end
What I have found as cause of the issue is that when I click on the link
= link_to "Export Records", student_path(:format => :csv)
#students is empty. I don't know why ? or how to solve the issue.
I am following this http://railscasts.com/episodes/362-exporting-csv-and-excel and it looks to be pretty straight forward. I have included 'csv' and have put the code in controller index file and in model.
Now when I am clicking on /products.csv, it do export the list of products in csv but instead of having actual data it is having entries like #, what am I doing wrong ?
EDIT - here is the product.rb
attr_accessible :name, :size, :email
def self.to_csv
CSV.generate do |csv|
csv << column_names
all.each do |product|
csv << product.attributes.values_at(*column_names)
end
end
end
In your products controller define a method as below:
def export_csv
#Products = Product.find(:all)
csv = CSV.generate do |csv|
# header row
csv << ["product_name","product_type"]
# data row
#products.each do |t|
csv << [t.product_name, t.product_type]
end
end
send_data(csv, :type => 'text/csv')
end
In your routes:
match 'csv' => 'products#export_csv', :as => :csv
In your view give a link for CSV:
link_to "CSV", csv_path