I have a form which when submitted takes all the input and generates a csv. I am using CSV.open in my model so that the file is sent to the server. However, even with this, there is a separate CSV file with a random CSV code that is generated. It does not contain any form details, however, it would be ideal if no CSV is downloaded at all. I just want to CSV to get uploaded to the server.
Model:
def csv
attributes = %w{ first_name last_name }
CSV.open("#{Rails.root}/public/#{self.first_name}.csv", "wb") do |csv|
csv << attributes
csv << [ self.first_name, self.last_name ]
end
end
controller:
def method
if conditions
student = Student.find(params[:id])
respond_to do |format|
format.html {redirect_to students_path, :notice => "Success"}
format.csv { send_data student.csv }
end
else
redirect_to students_path, :notice => "Declined"
end
end
Please let me know whats wrong
Related
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.
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 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.
I need to render my #manufacturers array to pdf, but do it only via click on some link in view...
Now i have such code
def index
#manufacturers = Manufacturer.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #manufacturers }
format.pdf { render :layout => false }
end
end
I see a lot of examples in web, but i didn't found clear and actual example... Just how simple do in a4 pdf table with my array #manufacturers ?
In addition to prawn, use the prawnto rails plugin to help with rendering the PDF as a template.
See https://github.com/prior/prawnto for the plugin and http://railscasts.com/episodes/153-pdfs-with-prawn for how to use it.
[Note: the Report gem currently only generates on letter-size paper, patch for A4 would be welcome!]
You can use the Report gem, which generates PDF using Prawn but also XLSX and CSV.
# a fake Manufacturer class - you probably have an ActiveRecord model
Manufacturer = Struct.new(:name, :gsa)
require 'report'
class ManufacturerReport < Report
table 'Manufacturers' do
head do
row 'Manufacturer report'
end
body do
rows :manufacturers
column 'Name', :name
column 'GSA?', :gsa
end
end
# you would want this so that you can pass in an array
# attr_reader :manufacturers
# def initialize(manufacturers)
# #manufacturers = manufacturers
# end
def manufacturers
[
Manufacturer.new('Ford', true),
Manufacturer.new('Fischer', false),
Manufacturer.new('Tesla', nil),
]
end
end
When you call report.pdf.path, a PDF is generating in the tmp directory:
report = ManufacturerReport.new
puts report.pdf.path #=> /tmp/185051406_Report__Pdf.pdf
puts report.xlsx.path #=> /tmp/185050541_Report__Xlsx.xlsx
You can do it in your controller like:
#manufacturers = Manufacturer.all
respond_to do |format|
format.html # index.html.erb
format.json { render json: #manufacturers }
format.pdf do
report = ManufacturerReport.new(#manufacturers) # using the commented-out code
send_file report.pdf.path, :type => 'application/pdf', :disposition => 'attachment', :filename => 'ManufacturersReport.pdf'
# tmp files are periodically cleaned up by the operating system, but if you want to be extra clean you can call
# report.cleanup
# but this may remove the tmp files before apache/nginx/etc. finishes delivering the file
end
end
End result:
PDF
XLSX
Note that the XLSX has an autofilter added for you automatically.
This is the field on form, I am using
<%= f.file_field :file ,:url=>{:controller=>"retailers",:action=>"csv_import"}%>
The following is the controller code
def create
#retailer = Retailer.new(params[:retailer])
respond_to do |format|
if verify_recaptcha(:model =>#retailer ) && #retailer .save
# To notify newly registered user.
retailer_ids = [#retailer.id]
Emailer.on_notify_retailer(retailer_ids, 1, 0)
sign_in #retailer
format.html { redirect_to pages_about_path}
flash[:notice1] = "Thank you for registering with Chindi."
flash[:notice2] = "We will process your application and get back to you within 48 hours. Once approved, you will be able to create negotiable deals that Consumers can tailor to their needs."
flash[:notice3] = "You will be able to create, manage and administer your deals and your buyers in this easy to use control panel."
format.json { render json: pages_about_path, status: :created, location: #retailer }
else
#title = "Sign up"
format.html { render action: "new"}
flash[:notice1] = "Incorrect word verification. Are you sure you\'re human?"
format.json { render json: #retailer.errors, status: :unprocessable_entity }
end
end
csv_parse()
end
The above code is used to save the data into database. The CSV file #retailer.file_file_name is to be stored in database as well as it needs to be parsed and the values need to be stored in fields
csv_parse is used to parse the csvfile
I am able to save file in data
now i need to parse the csv file and store the individual fields in another database.
the code for csv_parse is as follows.
def csv_parse
#parsed_file=CSV.foreach(params[:dump][:file].original_filename)
n=0
#parsed_file.each do |row|
User_list.create(
:email=>row[0],
:first_name=>row[1],
:last_name=>row[2]).save
flash.now[:message]="CSV parse Successful, #{n} new records added to data base"
end
end
when I run this it gives the following error/s.
You have a nil object when you didn't expect it!
You might have expected an instance of Array.
The error occurred while evaluating nil.[]
please help me with the above error why is it throwing such an error
thanks in advance.
I just paste some peace of working for me code and hope it will help you:
first_line = true
file = File.open File.join(Rails.root, 'tmp/import/category.csv')
file.each do |line|
unless first_line
row = CSV::parse_line(line, ';')
category = Category.find_by_name(row[1]) || Category.create(:name => row[1], :target => 'basic')
category.update_attribute(:import_id, row[0])
else
first_line = false
end
end
I sometime wrote this code to import categories to my DB. Here you can change CSV file name and block for each iterator. Also first_line is description for fields and I was ignoring it.
def create
#retailer = Retailer.new(params[:retailer])
respond_to do |format|
# ... same as above
end
csv_parse(params[:retailer][:file].path)
private
def csv_parse(path)
rows = CSV.read(path)
rows.each do |row|
User_list.create(:email=> row[0], :first_name=>row[1], :last_name=>row[2])
end
flash.now[:message]= "CSV parse Successful, #{rows.size} new records added"
end
end