Issue when I want to import CSV file - ruby-on-rails

I want to import users with a CSV file so I put this code in lib/task/import.rake :
require 'csv'
task :import => :environment do
CSV.foreach('db/test.csv', :headers => true) do |row|
UserManager::User.create!(row.hash)
end
end
Here is my CSV test file :
surname;name;email;password;password_confirmation
test;test;test#exemple.fr;pass;pass
And when I run rake import I get this error :
When assigning attributes, you must pass a hash as an argument.
Why did I get this error ?

To sum up the comment of Pavan and the solution of gunn, your code should be:
require 'csv'
task :import => :environment do
CSV.foreach('db/test.csv', :headers => true, col_sep: ';') do |row|
UserManager::User.create!(row.to_hash)
end
end

Those variables aren't comma separated, they're semicolon separated. So:
CSV.foreach('db/test.csv', headers: true, col_sep: ";")

I think it should be
require 'csv'
task :import => :environment do
CSV.foreach('db/test.csv', :headers => true) do |row|
UserManager::User.create!(row.to_hash)
end
end
row.hash will return an integer

Use this
require 'csv'
CSV.foreach(file.path, headers: false) do |row|
user_hash = {}
user_hash = {"surname"=> name,"last_name"=> last_name } #key value
User.create!(user_hash)
end
end

Try this ............
require 'csv'
#file with full path
file = "#{Rails.root}/public/file_name.csv"
#Reading file
user_file = CSV.read(file, :headers => true)
#Creating User
user = UserManager::User.where(:email => user_file['email']).first_or_create
if user.present?
user.name = user_file['email']
#Same other data ......
user.save!
end
Hope this will work for you.

Related

Using method within rake file tasks

A set of rake tasks of a .rake file are structured as follows
task :process_data => :environment do
CSV.foreach("scores.tsv", :col_sep => "\t", headers: true) do |row|
begin
[...]
repeated_method_a
ad-hoc_method
repeated_method_b
rescue StandardError => e
end
end
end
How should this rake file be structured to process sub-methods, such as:
def repeated_method_a
do_its_thing
end
You can simply add it under your task in the same file, so you have this:
task :process_data => :environment do
CSV.foreach("scores.tsv", :col_sep => "\t", headers: true) do |row|
begin
[...]
repeated_method_a
ad-hoc_method
repeated_method_b
rescue StandardError => e
end
end
end
def repeated_method_a
do_its_thing
end

How to import images from CSV and attach to model with ActiveStorage?

I'm trying to import users avatar from a CSV and attach to the users with ActiveStorage.
I've created a rake task for this, but it's not working (and do not throws any error). In my CSV there are only 2 fields: email and avatar (avatar is the url to the file, that is on another server).
This is the task:
require 'csv'
namespace :import do
desc "Import avatars to users from CSV"
task avatars: :environment do
filename = File.join Rails.root, "avatars.csv"
CSV.foreach(filename, headers: true, col_sep: ";", header_converters: :symbol) do |row|
User.find_by(email: row[:email]) do |u|
u.avatar.attach(URI.parse(row[:avatar]).open)
end
end
end
end
Any advice?
Thanks for your help.
Have you tried to catch the any exception and print the problem in the console?
Something like that:
require 'csv'
namespace :import do
desc "Import avatars to users from CSV"
task avatars: :environment do
begin
filename = File.join Rails.root, "avatars.csv"
CSV.foreach(filename, headers: true, col_sep: ";", header_converters: :symbol) do |row|
User.find_by(email: row[:email]) do |u|
u.avatar.attach(URI.parse(row[:avatar]).open)
end
end
rescue StandardError => e
logger = Logger.new(STDOUT)
logger.error e.message
logger.error e.backtrace.join("\n")
end
end
end
Also, are you sure you have users with that email?

Process CSV files in location relative to rake task

I have a rake task and CSV files that I need to process; they are located in sub-directory of the lib\tasks directory:
\foo
one.csv
two.csv
...
foo.rake
The task:
task foo: :environment do
# for each file in directory
Dir.foreach("./*.csv") do |file| # not valid
# process CSV file's content
CSV.foreach(file, {:headers => true, :col_sep => ";"}) do |row|
...
end
end # Dir
end # task
How do I references files that are relative to the rake task?
I got to thinking about this more and I think combining File.join and Dir.glob will allow you to process all your csv files:
require "csv"
foo_dir = File.join(Rails.root, "lib", "tasks", "foo")
task foo: :environment do
# for each file in directory
Dir.glob(foo_dir + "/*.csv") do |csv_file|
# process CSV file's content
CSV.foreach(csv_file, {:headers => true, :col_sep => ";"}) do |row|
#...
end
end # Dir
end # task
EDIT: As #craig pointed out in the comment below, this can be accomplished more succinctly by using File.dirname and __FILE__:
require "csv"
task foo: :environment do
# for each file in directory
Dir.glob(File.dirname(__FILE__) + "/*.csv").each do |file|
# process CSV file's content
CSV.foreach(csv_file, {:headers => true, :col_sep => ";"}) do |row|
#...
end
end # Dir
end # task

Requests spec post request No route matches error

I'm getting no route matches with rspec for testing a method in my controller.
Below is the test code:
let(:csv_file){ fixture_file_upload('files/sample_employee_data.csv', 'text/csv') }
describe "#process_csv" do
it "should output a valid csv file" do
post '/payslips/process_csv', :csv => csv_file, :header => 1
puts response
end
end
Below is my routes.rb file code:
PayCalculator::Application.routes.draw do
resources :payslips do
collection { post :process_csv }
end
root 'payslips#index'
end
Below is the method
def process_csv(uploaded_file = params[:files][:csv], headers = params[:files][:headers])
begin
rows = CSV_Manager.extract_csv(uploaded_file, headers)
rows.each do |row|
payslip = Payslip.create(
:first_name => row[0],
:last_name => row[1],
:annual_salary => row[2],
:superannuation => row[3].to_i,
:payment_start_date => row[4]
)
redirect_to root_url, notice: payslip.errors.full_messages and return unless payslip.valid?
prepare_output(row)
end
#rows = self.pay_data
csv_file = CSV_Manager.prepare_csv(#rows, ["Name", "Pay Period", "Gross Income", "Income Tax", "Net Income", "Superannuation"])
send_data csv_file, :type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment;filename=Payslip #{Date.today.to_s}.csv"
rescue
redirect_to root_url, notice: "CSV not supplied or invalid format"
end
end
When I run rspec spec/ I get below error:
Failure/Error: post '/payslips/process_csv', :csv => csv_file, :header => 1
ActionController::UrlGeneratorError:
No route matches...
What could be wrong in here that is causing this error?
params[:files][:headers] where you are passing :header => 1. Key is different. This will not cause no route found probably but just for correction. As per rails convention action doesn't has parameters
If you are going to pass optional params in any methods: Please have a look at : http://www.ruby-doc.org/docs/ProgrammingRuby/html/tut_methods.html
Following is the example of method defination:
def foo(arg1="Miles", arg2="Coltrane", arg3="Roach")
"#{arg1}, #{arg2}, #{arg3}."
end
Try this:
post :process_csv, :files => {:csv => csv_file, :header => 1}

Rails 3 Server Startup problem with fastercsv

I have a rails 2.3.5 app getting upgraded to Rails 3. I did every thing I am required to do for upgrading and when I start the rails server using
rails server
it gives me this
Please switch to Ruby 1.9's standard CSV library. It's FasterCSV plus
support for Ruby 1.9's m17n encoding engine.
I am using ruby-1.9.2-p0 and have fastercsv (1.5.3) gem installed. with the help of puts statements, i was able to track down where the error occurred. i found that the execution stops at this line
Bundler.require(:default, Rails.env) if defined?(Bundler)
in application.rb file. I tried many things but none worked .. please help..
Remove fasterCSV from your Gemfile in the application. Bundler is trying to require FasterCSV because you have it specified in the Gemfile.
with 1.9 you no longer need/can use the fastercsv gem, since it's bundled in the std lib.
Now you just need to do:
require 'csv'
CSV.open("temp.csv", "w") do |csv|
csv << ["line1row1", "line1row2"]
csv << ["line2row1", "line2row2"]
# ...
end
This is the solution i found:
require 'fastercsv'
require 'csv'
class ImportFileToAssetsWithFasterCsv < ActiveRecord::Migration
def self.up
if CSV.const_defined? :Reader
csv = FasterCSV
else
csv = CSV
end
file = 'db/staticfiles/DB-good-rightnames-forimport.csv'
csv.foreach(file) do |row|
Asset.create!(:country => row[0], :city => row[1], :latlong => row[2], :XX => row[3], :DEC => row[4], :point_name => row[5], :system_type => row[6], :system_brand => row[7], :function => row[8], :operator_name => row[9], :operator_brand => row[10], :parent_company => row[11], :app => "WWW", :language => "en", :source => "XXX", :Z_name => "International", :pref_format => "")
end
end
def self.down
IspcAsset.destroy_all()
end
end
Look here too http://www.wherethebitsroam.com/blogs/jeffw/fastercsv-csv-ruby-18-19-and-rails-30
If used FasterCsv in loop or in the code just change it with Csv and works for me.
Remove gem 'fastercsv' from gem file.
Just write your code in controller, no need add other code in somewhere in config.
This is the example of wrong code.
class HomeController < ApplicationController
require 'fastercsv'
def download_csv
#invitation = Invitation.find(params[:id])
#activities = Version.where("created_at >= ?", #invitation.created_at)
if params[:export]
csv_string = FasterCSV.generate do |csv|
# header row
csv << ["Date", "Event", "Details"]
#activities.each do |act|
csv << [act.created_at.strftime("%d-%m-%Y"), act.event, act.item_id]
end
end
timestamp = Time.now.strftime('%Y-%m-%d_%H:%M:%S')
send_data csv_string,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=goal_history_#{timestamp}.csv"
end
end
and just corrected with changing word FasterCsv to Csv and it works. like below
class HomeController < ApplicationController
require 'csv'
def download_csv
#invitation = Invitation.find(params[:id])
#activities = Version.where("created_at >= ?", #invitation.created_at)
if params[:export]
csv_string = CSV.generate do |csv|
# header row
csv << ["Date", "Event", "Details"]
#activities.each do |act|
csv << [act.created_at.strftime("%d-%m-%Y"), act.event, act.item_id]
end
end
timestamp = Time.now.strftime('%Y-%m-%d_%H:%M:%S')
send_data csv_string,
:type => 'text/csv; charset=iso-8859-1; header=present',
:disposition => "attachment; filename=goal_history_#{timestamp}.csv"
end
end

Resources