I have #people variable contains data look exactly like:
What I have
[{"id"=>1, "name"=>"Tom", "age"=>"25"},
{"id"=>2, "name"=>"Marry", "age"=>"27"},
{"id"=>3, "name"=>"Jack", "age"=>"28"}]
and I am trying to convert the data to the CSV file, which might look like
What I am aiming to do
id | name | age
1 | Tom | 25
2 | Marry| 27
3 | Jack | 28
but my code generates a CSV file with displaying all of the data inline. For example:
What I get
{"id"=>1,"name"=>"Tom","age"=>25},{"id"=>2, "name"=>"Marry",
"age"=>"27"},{"id"=>3, "name"=>"Jack", "age"=>"28"}
What I did:
to_csv action look like:
def to_csv
CSV.generate(option) do |csv|
csv << column_names
values.each do |value|
csv << value.attributes.values_at(*column_names)
end
end
end
I added this respond_to block to one of my actions:
respond_to do |format|
format.html
format.csv {
send_data #people.to_csv,
filename: "export.csv",
type: 'text/csv; charset=utf-8'
}
I am getting data(e.g {"id"=>1,"name"=>"Tom","age"=>25 ...) from external so I pushed that data into #people variable to use. Any help would be very appreciated.
I think you need to write the function differently:
def to_csv(people)
CSV.generate do |csv|
return unless people.count > 0
csv << people[0].keys
people.each do |person|
csv << person.values
end
end
end
I suppose you could even do:
def to_csv(people)
CSV.generate do |csv|
return unless people.count > 0
csv << people[0].keys
csv << people.each.map{|item| item.values}
end
end
And then call it as a function:
respond_to do |format|
format.html
format.csv {
send_data to_csv(#people),
filename: "export.csv",
type: 'text/csv; charset=utf-8'
}
you Don't need to do like value.attributes.values_at(*column_names) just you need to do value.values which will give you the array of values that you want to store it in CSV.
for example
people = [{"id"=>1, "name"=>"Tom", "age"=>"25"},
{"id"=>2, "name"=>"Marry", "age"=>"27"},
{"id"=>3, "name"=>"Jack", "age"=>"28"}]
def to_csv
CSV.generate(headers: true) do |csv|
csv << column_names
people.each do |person|
csv << person.values
end
end
end
Here is how i do mine,
in my controller i added
respond_to do |format|
format.html
format.csv { send_data #people.to_csv }
end
then
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |project|
csv << people.attributes.values_at(*column_names)
end
end
end
then dont forget to require 'csv' in your config/application.rb
then you can link to your csv with something like <%= link_to "CSV", people_path(format: "csv") %>
Since I ended up using a csv method and not a json method I thought it might be a good Idea to change the question name and remove the part with the json if other people might have the same problem someday.
Update: I've tried using this as a way to export data.
In my controller I have the following:
def profile
#user = User.find(params[:id])
#user_posts = #user.posts.order('created_at DESC')
respond_to do |format|
format.html
format.csv { send_data #user.csv, filename: "userinfo-#{Date.today}.csv" }
end
end
In my view :
<p><%= link_to("Generate Report", user_path(#user, format: :csv), class: "btn btn-success",) %></p>
In my user.rb :
def csv
CSV.generate do |csv|
csv << column_names
all.each do |item|
csv << item.attributes.values_at(*column_names)
end
end
end
Update 2: Managed to fix it myself, I was using a wrong csv method in my Controller. Replacing it with the following :
def csv
CSV.generate do |csv|
csv << %w{ user_id user_username user_email }
csv << [ self.id, self.username, self.email]
end
end
works like a charm.
Best regards
I want to recover data in two different tables and put the data on excel but I have a little bug if someone has an idea. Thank you
class ExportController < ApplicationController
def index
#attachments= Attachment.all
#projects= Project.all
respond_to do |format|
format.html
format.csv {send_data #attachments.to_csv}
format.xls {send_data #attachments.to_csv(col_sep: "\t") and send_data #projects.to_csv(col_sep: "\t")}
end
end
end
route.rb
get '/export', to: 'export#index'
model..
class Export < ActiveRecord::Base
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |table|
csv << table.attributes.values_at(*column_names)
end
end
end
end
view
<h1>Exportation</h1>
<%= link_to 'Download as .xlsx', export_path(format: :xls) %>
model (project.rb)
class Project < ActiveRecord::Base
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |project|
csv << project.attributes.values_at(*column_names)
end
end
end
end
model (attachment.rb)
class Attachment < ActiveRecord::Base
def self.to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |table|
csv << table.attributes.values_at(*column_names)
end
end
end
end
error image
You can't respond twice one request. An option would be:
format.xls {send_data #attachments.to_csv(col_sep: "\t") + #projects.to_csv(col_sep: "\t") }
With this, you'll respond with one file containing attachments and projects.
It's simple..
when I write it in my controller like this.
def index
#articles = News.order(:id)
respond_to do |format|
format.html
format.csv { render text: #articles.to_csv}
end
end
and in news.rb
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
What I expected when I open my site(http://localhost:3000/mycontroller.csv) is shows the text in my screen.
However, it just download csvfile..... Even when I changed render text to html.
What is wrong in my code?
You can try this code
class HomeController < ApplicationController
respond_to :html, :json, :csv
def index
#modelnames = Modelname.all
respond_with(#modelnames)
end
end
I'd like to export all database entries into a csv using Rails 3.2. I've been following these instructions:
My controller:
EDIT: I've changed from class method to instance method
...
elsif params[:reference] == 'exportnews'
#data = News.find(:all, :order => "date_posted desc", :conditions => "#{Settings.show} = 1", :limit => "5")
respond_to do |format|
format.html { redirect_to root_url }
format.csv { send_data #data.to_csv }
end
else
...
My model:
class News < ActiveRecord::Base
attr_accessible :content, :date_posted, :heading, :hidden, :reference, :title, :user
def to_csv(options = {})
CSV.generate(options) do |csv|
csv << column_names
all.each do |product|
csv << product.attributes.values_at(*column_names).map(&:to_csv)
end
end
end
end
yet when I visit the specified url (I've created a route in config/routes.rb I get a csv file with the following details:
#<News:0x007fef657d69f8> #<News:0x007fef632b95a8> #<News:0x007fef632b8ec8> #<News:0x007fef632b8680> #<News:0x007fef632b7e38>
What am I missing?
Looks like you're not calling your method this way (you're calling the original .to_csv method instead. Try doing this in your view:
format.csv { send_data #data.map(&:to_csv }