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
Related
controller code
def index
#courses = Course.all
respond_to do |format|
format.html
format.csv { send_data #courses.to_csv }
end
end
Link code
<%= link_to "Export Course", courses_path(format: :csv) %>
model code
def self.to_csv
CSV.generatezz do |csv|
csv << column_names
all.each do |product|
csv << product.attributes.values_at(*column_names)
end
end
end
With that code, I can properly export a csv file that contains every course in the database. I want to set it up where I can export only the information of one course. If possible i'd like to use a variable(like a url parameter) as I have other tables I want to iterate over with the same id that would let me get one course to the csv.
The model code is a class method, which annoyingly enough won't work for an instance of that class, so I can't, in the controller, go #courses = Course.find(params[:course_id].to_i) and then send_data #courses.to_csv, as it acts as if its an entirely new thing.
Any help on this would be great, thanks.
What if you made an instance method:
def to_csv
CSV.generatezz do |csv|
csv << column_names
csv << attributes.values_at(*column_names)
end
end
I dont know what column_names is here, maybe another method you made? Anyhow, you should be able to call that in your controller after you set the #course variable with #course = Course.find(params[:id])
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") %>
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 is partly working. It generates the file but the output is not how I want it.
Controller
#messages = Message.take(2)
respond_to do |format|
format.html
format.csv { send_data #messages.to_csv }
end
Message.rb
def self.to_csv
CSV.generate do |csv|
csv << Message.attribute_names
Message.all.each do |message|
csv << message.attributes.values
end
end
end
I get the CSV file downloaded, it contains the records itself but it does not show the columns and values
#<Message:0x007fca7a028338>,#<Message:0x007fca79a6bf58>
I would expect the Message attributes like:
ID,text
1,hello
2,world
Message.take(2) returns Array. You need ActiveRecord::Relation.
Try Message.limit(2)
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)