I have a bit of code that checks if a user is in the "sakai_trained" array before proceeding. For some reason when I run this code:
CSV.foreach(activation_csv, {:headers => true}) do |row|
if sakai_trained
row << 'Untrained' unless sakai_trained.include?(row[1])
end
course_list << row
end
I get this error
C:/Ruby193/lib/ruby/1.9.1/csv.rb:478:in `==': undefined method `row' for "stuartademo":String (NoMethodError)
from activate-courses.rb:42:in `include?'
from activate-courses.rb:42:in `block in <main>'
from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1792:in `each'
from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1208:in `block in foreach'
from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1354:in `open'
from C:/Ruby193/lib/ruby/1.9.1/csv.rb:1207:in `foreach'
from activate-courses.rb:40:in `<main>'
I thought at first it was having a problem with the row[1] but it breaks the same way even with a string literal. I checked to make sure the sakai_trained array exists AND has data in it as well. I also tried rewriting it as an if statement in case the unless logic was flawed but that also returns the same error.
In case it's unclear, I want to check that the userid located in row[1] exists in the sakai_trained array before adding the row to the course_list array. If it doesn't, I want 'Untrained' added to the row first, then the row added to the array. When I removed the unless... part I was able to get a complete course_list array, but as expected, every row has "untrained". The problem appears to be with the
unless sakai_trained.include?(row[1])
part but I just can't see it.
Update:
sakai_trained = []
CSV.foreach(training_csv, {:headers => true}) do |trained|
sakai_trained << trained
end
Should I #map! each item with .to_s to make them into strings then?
Update 2:
I changed
sakai_trained << trained
to
sakai_trained << trained.to_s
and it's removed the error, but the output still isn't quite right.
Update 3: ALMOST. WORKING. You guys are all incredibly awesome, and as frustrating as this is I have learned some new and interesting things.
Code:
course_list = []
if options[:verify]
sakai_trained = []
CSV.foreach(training_csv, {:headers => true}) do |trained|
sakai_trained << trained.to_s
end
end
CSV.foreach(activation_csv, {:headers => true}) do |row|
if sakai_trained && !sakai_trained.include?(row[1])
row << 'Untrained'
end
course_list << row
end
Yields:
2124-5318,stuartademo,Untrained
2124-5320,bobsmith,Untrained
2124-4686,jimsmith,Untrained
2124-3560,jillsmith,Untrained
2124-3562,suesmith,Untrained
2124-5428,harrysmith,Untrained
When it should be
2124-5318,stuartademo,Untrained
2124-5320,bobsmith
2124-4686,jimsmith
2124-3560,jillsmith
2124-3562,suesmith
2124-5428,harrysmith
The problem is occurring inside the csv.rb
file in the standard Ruby library on line 478. Here's the CSV
code that is causing the problem for you:
#
# Returns +true+ if this row contains the same headers and fields in the
# same order as +other+.
#
def ==(other)
@row == other.row
end
From the looks of your error message, the String "stuartademo"
is being passed into this method and, of course, there is no String#row
. It looks like other
should be a row of a csv file. According to the comments on the above method, it should contain headers and fields.
I would suggest finding where this String "stuartademo"
is coming from and figure out why only the String is getting passed in instead of the entire row.
EDIT:
If sakai_trained
is populated from a CSV, then it is not an array but rather CSV:Row
type. In this case, when you call CSV::Row#include?
then the ==(other)
is getting called. Hence, what you are passing into is, row[1]
is a String. It should not be a String.
Instead of using include?
, try using field?(data)
or fields.include?
.
CSV.foreach(activation_csv, {:headers => true}) do |row|
if sakai_trained
row << 'Untrained' unless sakai_trained.field?(row[1])
end
course_list << row
end