Rails - Passing an Active Record relation into a CSV - ruby-on-rails

I'm trying to filter through all venues, and add any without an external_join_url to the CSV I've created.
require 'csv'
namespace :create_dump do
desc "Erase and fill database"
task :venue => :environment do
#venues = Venue.where(external_join_url: nil)
CSV.open("venues_without_join_url.csv", "w") do |csv|
csv << ["Venue Title"]
#venues.each do |venue|
csv << venue.title
end
end
end
end
When I attempt to do so, I get the error:
NoMethodError: undefined method `map' for "5 Pancras Square":String
I get this means I'm trying to map a string, but can't see what part I'm creating the string. I've tried different ways of assigning #venues (creating an array and shovelling into it) to no avail.

csv << expects an array of strings that's meant to be the fields of a row in the csv file
require 'csv'
namespace :create_dump do
desc 'Erase and fill database'
task venue: :environment do
#venues = Venue.where(external_join_url: nil)
CSV.open('venues_without_join_url.csv', 'w') do |csv|
csv << ['Venue Title']
#venues.each do |venue|
csv << [venue.title]
end
end
end
end

Related

How to check header exist before import data in Ruby CSV?

I want to write header only 1 time in first row when import data to csv in ruby, but the header is written many time on output file.
job_datas.each do |job_data|
#company_job = job data coverted etc....
save_job_to_csv(#company_job)
end
def save_job_to_csv(job_data)
filepath = "tmp/jobs/jobs.csv"
CSV.open(filepath, "a", :headers => true) do |csv|
if csv.blank?
csv << CompanyJob.attribute_names
end
csv << job_data.attributes.values
end
end
Any one can give me solution? Thank you so much!
You are calling save_job_to_csv the method for each job_data and pushing header every time csv << CompanyJob.attribute_names
filepath = "tmp/jobs/jobs.csv"
CSV.open(filepath, "a", :headers => true) do |csv|
# push header once
csv << CompanyJob.attribute_names
# push every job record
job_datas.each do |job_data|
#company_job = job data coverted etc....
csv << #company_job.attributes.values
end
end
The above script can be created wrapped a method but if you like to write a separate method that just saves the CSV, then you need to refactor the script when you first prepare an array of values holding header and pass it to a method that just saves to CSV.
You could do something similar to this:
def save_job_to_csv(job_data)
filepath = "tmp/jobs/jobs.csv"
unless File.file?(filepath)
File.open(filepath, 'w') do |file|
file.puts(job_data.attribute_names.join(','))
end
end
CSV.open(filepath, "a", :headers => true) do |csv|
csv << job_data.attributes.values
end
end
It just checks beforehand if the file exists and if not it adds the header. If you want tabs as column separators, you just have to change the value for the join function and add the col_sep parameter to CSV.open():
file.puts(job_data.attribute_names.join("\t"))
CSV.open(filepath, "a", :headers => true, col_sep: "\t") do |csv|

How to export the entire active records in a schema to a csv file

Is there a way to achieve exporting the entire active records in a rails application to csv where each relation is a sheet of csv or there is another way to export full db data.Any suggestions?
Try like this you can get datas from your tables. after you can split it by sheet
models = ActiveRecord::Base.connection.tables
models.shift
models.shift
models.map do |model_name|
model_name = model_name.split("")
model_name.pop
model_name = model_name.join("")
model_name.camelize.constantize.all.map do |data|
puts data
end
end
def backup
models = ActiveRecord::Base.connection.tables
all_data = Hash.new
models.map do |model_name|
table_data = []
model_name = model_name.split("")
model_name.pop
model_name = model_name.join("")
model_name.camelize.constantize.all.map do |data|
table_data.push(data)
end
all_data[model_name.camelize] = table_data
end
send_data export_csv(all_data), filename: "Backup - #{Date.today}.csv" and return
end
def export_csv(data)
csvfile = CSV.generate(headers: true) do |csv|
data.each do |key, value|
csv << [key]
attributes = key.camelize.constantize.column_names
csv << attributes
value.each do |val|
csv << val.attributes.values_at(*attributes)
end
csv << ['eot']
end
end
return csvfile
end
I found the solution and a way to export all tables inside a single csv file.

Data is overwriting instead of appending to CSV

I am using a rake task and the csv module to loop through one csv, extract and alter the data I need and then append each new row of data to a second csv. However each row seems to be overwriting/replacing the previous row in the new csv instead of appending it as a new row after it. I've looked at the documentation and googled but can't find any examples of appending rows to the csv differently.
require 'csv'
namespace :replace do
desc "replace variant id with variant sku"
task :sku => :environment do
file="db/master-list-3-28.csv"
CSV.foreach(file) do |row|
msku, namespace, key, valueType, value = row
valueArray = value.split('|')
newValueString = ""
valueArray.each_with_index do |v, index|
recArray = v.split('*')
handle = recArray[0]
vid = recArray[1]
newValueString << handle
newValueString << "*"
variant = ShopifyAPI::Variant.find(vid)
newValueString << variant.sku
end
#end of value save the newvaluestring to new csv
newFile = Rails.root.join('lib/assets', 'newFile.csv')
CSV.open(newFile, "wb") do |csv|
csv << [newValueString]
end
end
end
end
Your mode when opneing the file is wrong and should be a+. See details in the docs: http://ruby-doc.org/core-2.2.4/IO.html#method-c-new
Also, you might want to open that file just once and not with every line.

Rails - Export DB to CSV not reading from translation file

I've seen a number of useful suggestions here but so far haven't been able to fix my problem. I'm creating a redmine plugin (ruby on rails) and I have a button that exports the db into a CSV file. That part works just fine.
My problem is that the column names in the csv file are not being translated don't seem to be changed by a call to human_attribute_name. Can anybody point out where i've gone wrong and help me correct it?
I mostly followed this tutorial: http://railscasts.com/episodes/362-exporting-csv-and-excel?view=asciicast
app/models/person.rb
def self.to_csv(options={})
CSV.generate(options) do |csv|
csv << User.attribute_names.map {|c| User.human_attribute_name(c)}
# Could I instead use:
# csv << User.human_attribute_names
User.all.each do |user|
csv << user.attributes.values
end
end
end
config/locales/en.yml
en:
activerecord:
attributes:
user:
col1: "Column 1"
col2: "Column 2"
Found this solution which seems to work:
app/models/user.rb
def self.to_csv(options={})
CSV.generate(options) do |csv|
#cols = User.attribute_names #[1..-1] to remove first column from output
csv << #cols.map { |c| I18t.t c, scope: [:activerecord, :attributes, :user] }
User.all.each do |user|
csv << user.attributes.value_at(*#cols)
end
end
end

Rails CSV Export - Adding custom field

I'm building an ecommerce app in Rails. I have a method to export the Order model with shipping details. The below method works as-is but I want to add a column into the export from another model.
My order model has a product_id which joins with the product table that has the product name. I want to add the product name. So something like order.product.name. How would I go about adding that into the below?
Here is my method in my order.rb:
def self.to_csv(orders)
wanted_columns = [:id, :shipname, :shipaddress, :shipcity, :shipstate, :shipzip]
CSV.generate do |csv|
csv << wanted_columns
orders.each do |order|
csv << order.attributes.values_at(*wanted_columns)
end
end
end
You can simply add it to your line, like so:
def self.to_csv(orders)
wanted_columns = [:id, :shipname, :shipaddress, :shipcity, :shipstate, :shipzip]
CSV.generate do |csv|
csv << wanted_columns.insert(-1, :product_name)
orders.each do |order|
csv << order.attributes.values_at(*wanted_columns).insert(-1, order.product.name)
end
end
end
The insert method inserts the given values before the element with the given index.
Negative indices count backwards from the end of the array, where -1 is the last element.
It returns the resulting array.
To simplify, in this case, this:
wanted_columns = [:id, :shipname, :shipaddress, :shipcity, :shipstate, :shipzip]
CSV.generate do |csv|
csv << wanted_columns.insert(-1, :product_name)
end
Should behave exactly the same as:
CSV.generate do |csv|
csv << [:id, :shipname, :shipaddress, :shipcity, :shipstate, :shipzip, :product_name]
end
The same principal applies to the array generated by:
order.attributes.values_at(*wanted_columns)
If this is not working, try the simplified example, and inspect the array for correctness prior to adding it to the array. You may additionally simplify:
orders.each do |order|
csv << order.attributes.values_at(*wanted_columns).insert(-1, order.product.name)
end
to:
csv << orders.first.attributes.values_at(*wanted_columns).insert(-1, orders.first.product.name)
For purposes of troubleshooting...

Resources