Rails 4 download to CSV - ruby-on-rails

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.

Related

rails exporting csv in background

I have made an csv importer and exporter in rails for article model.
It takes the articles and downloads it in the csv format.
It is working fine but I want it to be in a backgrond process.
Can anyone tell how to perform the import and export in background.
Here are my files which I have used-
Article_controller
def index
#articles = Article.all
#articles = Article.includes(:user)
respond_to do |format|
format.html # index.html.erb
format.json { render json: #articles }
format.atom
#articles = Article.order(:name).page params[:page]
format.csv { send_data #articles.to_csv, filename: "#{current_user.email}-#{Date.today}.csv" }
end
end
...
article.rb
def self.import(file,userid)
user = User.find_by(id: userid)
if user
CSV.foreach(file.path, headers: true) do |row|
user.articles.create! row.to_hash
end
end
end
def self.to_csv
attributes = %w{id title content}
CSV.generate(headers: true) do |csv|
csv << attributes
all.each do |article|
csv << article.attributes.values_at(*attributes)
end
end
end
Import:
The import is easier, because the users do not necessarily have to receive feedback after import is done.
As mentioned in the comments you can use ActiveJob with a backend like sidekiq:
You could use a background job in your article.rb:
def self.import(file, userid)
CSVImportJob.perform_later(file.path, userid)
end
class CSVImportJob
def perform(filepath, userid)
user = User.find_by(id: userid)
if user
CSV.foreach(filepath, headers: true) do |row|
user.articles.create! row.to_hash
end
end
end
end
Export:
The export is trickier, because you cannot send a file to user from a background job. You can either poll the results from the browser or send a websocket notification with ActionCable
The background processing would look similar to the import:
def self.export
CSVExportJob.perform_later
end
class CSVExportJob
def perform
attributes = %w{id title content}
CSV.generate(headers: true) do |csv|
csv << attributes
Article.find_each do |article|
csv << article.attributes.values_at(*attributes)
end
end
# Save CSV somewhere and notify its readiness
end
end
Then you would have to create a different route for triggering the CSV creation.
And the ArticleController#index would always return the last exported CSV, that is saved somewhere in the DB or file system.

Downloading an sqlite 3 database in rails as a csv file

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).

Rails export to CSV file

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)

Why rails download csv file when I want to show html using render :text or html?

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

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