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.
Related
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 need your help! I Have a simple database that I would like to download as a csv file.
Here is The Database:
class CreateTeams < ActiveRecord::Migration[5.1]
def change
create_table :teams do |t|
t.integer :name
t.integer :match
t.string :scout
t.timestamps
end
end
end
I would like to have a button on the program that I'm making to download the database, probably in the index.html.erb.
Here is my Teams controller:
class TeamController < ApplicationController
def index
#teams = Team.all
end
def new
#team = Team.new
end
def create
#team = Team.new(team_params)
respond_to do |format|
if #team.save
format.js
redirect_to '/team/index'
else
format.json { render json: #team.errors.messages, status: :unprocessable_entity }
end
end
end
private
def team_params
params.require(:team).permit(:name, :scout, :match)
end
end
I need your help please!
You can read the model attributes and push it to a csv string.
def index
csv_string = CSV.generate do |csv|
# header
csv << Team.attribute_names
Team.all.each do |team|
csv << team.attributes.values
end
end
respond_to do |format|
format.csv { render csv: csv_string, filename: 'teams.csv' }
end
end
Or you can also use this ruby gem comma, which does exactly the same thing as what you need. Add the gem in your Gemfile, install and you can use it like:
def index
respond_to do |format|
format.csv { render csv: Team.limit(50) }
end
end
Put this in your model:
def self.to_csv
attributes = %w{name match scout}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |team|
csv << team.attributes.values_at(*attributes)
end
end
end
Then in your view (add index action in controller):
<%= link_to "CSV", teams_path(format: "csv") %>
Then in your controller add under
#teams = Team.all
format.csv { send_data #teams.to_csv, filename: "Teams-#{Date.today}.csv"
And you should be good to go. You may need to add the index action to your routes if you didn't use "resources"
I found a way to do this, but thanks to all the people that posted an answer!
First, you put this in your rails model:
def self.to_csv
attributes = %w{number match scout}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |team|
csv << team.attributes.values_at(*attributes)
end
end
end
Then you put This in your routes:
resources :teams
Then you put this in your Teams controller index action:
def index
#team = Team.all
respond_to do |format|
format.html
format.csv {send_data #team.to_csv}
end
end
and in your application.rb add
require 'csv'
If you want to view the code, go to 'localhost:3000/teams.csv' and it will download it as a csv file and it will open in Microsoft Excel(if you have it as your default).
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'm building a marketplace app so sellers can list items to sell. I'm trying to download a CSV by seller so sellers can download their own listings.
I'm following the code in this railscast. I got the railscasts code to work as-is. It downloads all the data from my model into a csv. But when I add a seller filter to the query, it doesn't apply the filter.
In listings_controller:
def index
#listings = Listing.not_expired.order("created_at DESC")
respond_to do |format|
format.html
format.csv { send_data #listings.to_csv }
end
end
def seller
#listings = Listing.where(user: current_user).order("created_at DESC")
respond_to do |format|
format.html
format.csv { send_data #listings.seller_csv }
end
end
in listing.rb:
def self.to_csv
CSV.generate do |csv|
csv << column_names
all.each do |listing|
csv << listing.attributes.values_at(*column_names)
end
end
end
def self.seller_csv
CSV.generate do |csv|
csv << column_names
where(user: current_user).each do |listing|
csv << listing.attributes.values_at(*column_names)
end
end
end
The to_csv methods works fine and downloads all listings. But the seller_csv method also downloads all listings. I need it to filter by current_user. What am I missing?
Make your function take a list of listings as parameter.
def self.to_csv(listings)
CSV.generate do |csv|
csv << column_names
listings.each do |listing|
csv << listing.attributes.values_at(*column_names)
end
end
end
Then you cane re-use the same function in the two scenarios
def index
#listings = Listing.not_expired.order("created_at DESC")
respond_to do |format|
format.html
format.csv { send_data Listing.to_csv(#listings) }
end
end
def seller
#listings = Listing.where(user: current_user).order("created_at DESC")
respond_to do |format|
format.html
format.csv { send_data Listing.to_csv(#listings) }
end
end
Your code didn't make really sense as you were fetching listings in your controller but never re-used those fetched objects and was re-calling DB in your model's static functions.