rails exporting csv in background - ruby-on-rails

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.

Related

How do I export a filtered table to CSV?

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

Ruby on Rails - export user data to csv - button

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

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)

Rails 4 download to CSV

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.

Resources