5

I have an application on which I want to provide the feature to import the records from CSV and Excel file formats. I am using roo gem for it, but at the time of importing it gives the error "uninitialized constant Student::Roo".

Here is the code :

student.rb

def self.import(file)
  spreadsheet = open_spreadsheet(file)
  header = spreadsheet.row(1)
  (2..spreadsheet.last_row).each do |i|
    row = Hash[[header, spreadsheet.row(i)].transpose]
    product = find_by_id(row["id"]) || new
    product.attributes = row.to_hash.slice(*accessible_attributes)
    product.save!
  end
end


def self.open_spreadsheet(file)
  case File.extname(file.original_filename)
  when ".csv" then Roo::Csv.new(file.path, nil, :ignore)
  when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
  when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore)
  else raise "Unknown file type: #{file.original_filename}"
  end
end

student_controller.rb :

def import
    Student.import(params[:file])
    #puts @session[:current_organization_id].inspect
    redirect_to students_path, notice: "Record imported Successfully."
  end

new.html.erb :

<%= form_tag import_students_path, multipart: true do %>
        <%= file_field_tag :file , :required=> true%> <br/>
        <%= submit_tag "Import" , :class => "btn btn-primary btn-block" %>
<% end %>   

Gemfile :

source 'https://rubygems.org'
gem 'rails', '4.2.0'
gem 'mysql2'
gem 'sass-rails', '~> 5.0'
gem 'uglifier', '>= 1.3.0'
gem 'coffee-rails', '~> 4.1.0'
gem 'therubyracer', platforms: :ruby
gem 'jquery-rails'
gem 'jbuilder', '~> 2.0'
gem 'sdoc', '~> 0.4.0', group: :doc
gem 'sass', '3.2.19'
gem 'bower-rails'
gem 'font-awesome-sass'
gem 'devise'
gem 'roo'
group :development, :test do
    gem "rspec-rails", "~> 2.0"
    gem "factory_girl_rails", "~> 4.0"
    gem "capybara"
    gem "database_cleaner"
    gem "selenium-webdriver"
end

student.csv : This is the test data for student.

enrollment_no,roll_no,address,father_name
11,21,test,test
17,21,test,test
18,21,test,test
19,21,test,test
20,21,test,test
22,21,test,test
23,21,test,test
24,21,test,test
Nitesh Mishra
  • 570
  • 1
  • 4
  • 18

2 Answers2

2

It's not Roo::Csv, it's Roo::CSV. So the code should like

def self.open_spreadsheet(file)
  case File.extname(file.original_filename)
  when ".csv" then Roo::CSV.new(file.path, nil, :ignore)
  when ".xls" then Roo::Excel.new(file.path, nil, :ignore)
  when ".xlsx" then Roo::Excelx.new(file.path, nil, :ignore)
  else raise "Unknown file type: #{file.original_filename}"
  end
end

btw, no need to do require 'roo'

Santanu Karmakar
  • 326
  • 1
  • 3
  • 10
  • still i am getting the error "uninitialized constant Roo" – Nitesh Mishra Jul 08 '15 at 10:59
  • This is not the problem. If there is a `::Roo` class defined, it will be found in the `Student` scope. If unfound, then rails looks for `Student::Roo` and fails if also unfound. – dgilperez Jul 08 '15 at 11:08
  • Dear @dgilperez please check before downvoting and making a comment. There won't be a class defined ::Roo, it's defined in global scope. The problem is actually, it should be Roo::CSV, not Roo::Csv – Santanu Karmakar Jul 08 '15 at 11:18
  • @SKR that is not what your answer says. You do can call `Roo` (the namespacing module) without `::` and it will be found, if required at the top of the file. The issue is not with adding or not adding `::` to the class instantiation. That's why my downvote. – dgilperez Jul 08 '15 at 11:28
1

First, after @SKV comment: the correct name for CSV class is Roo::CSV and not Roo::Csv.

If the error persists, then it means that any of the Roo classes (Roo::CSV, Roo::Excel, etc) is not defined at this point in Student class. This probably means that, while you probably added the roo gem to your Gemfile and bundled, you need to require roo wherever you want to use the gem. This is mentioned in the gem docs.

Add require 'roo' to the top of student.rb file and it should work fine:

# student.rb
require 'roo'  # <==== 

class Student < ActiveRecord::Base
  def self.open_spreadsheet(file)
    ...
  end
end
dgilperez
  • 10,716
  • 8
  • 68
  • 96
  • 1
    After using require 'roo' on the student.rb file i am getting the error "cannot load such file -- roo" – Nitesh Mishra Jul 08 '15 at 10:57
  • Can you show us your Gemfile? Did you run `bundle install` and restarted the server? – dgilperez Jul 08 '15 at 10:58
  • I have added the gem file and also i have run the bundle install and after that when i restart the server it gives the error 'cannot load such file -- iconv (LoadError)'. – Nitesh Mishra Jul 08 '15 at 11:09
  • I don't know which gem or code requires iconv in your case, but add this to your gemfile: `gem "iconv"` and then run `bundle install` and restart – dgilperez Jul 08 '15 at 11:12
  • Also, which version of `roo` are you using? That is shown in your bundle install console output. If it is not the last version, run `bundle update roo` and restart. – dgilperez Jul 08 '15 at 11:14
  • After running the bundle update roo, my roo version is updated to 2.0.1 but still i am getting the error 'uninitialized constant Roo::Csv'. – Nitesh Mishra Jul 08 '15 at 11:20
  • It's Roo::CSV, not Roo::Csv, and you don't need to require roo – Santanu Karmakar Jul 08 '15 at 11:24
  • Updated answer. You need to use `Roo::CSV` instead of `Roo::Csv` (thanks @SKR for noticing) – dgilperez Jul 08 '15 at 11:26
  • My problem is solved now but getting a new "error undefined method `[]' for nil:NilClass" at the line header = spreadsheet.row(1). – Nitesh Mishra Jul 08 '15 at 11:36
  • That looks like another different question. I suggest you close this one and start a new one so we can help you better. You'll need to provide also info about the file you're uploading. – dgilperez Jul 08 '15 at 11:42
  • I don't have permission to post more than one question within 90 second so please continue with this only. I am importing csv file into it than it gives the error "error undefined method `[]' for nil:NilClass" on this line "header = spreadsheet.row(1) " . – Nitesh Mishra Jul 08 '15 at 11:59
  • I also have add student.csv file above. – Nitesh Mishra Jul 08 '15 at 12:02
  • 90 seconds? No, please, new question. If you don't, this one will probably get deleted anytime for being confusing. – dgilperez Jul 08 '15 at 14:31
  • Ok! Also, if this question was solved, you could consider accepting it. – dgilperez Jul 10 '15 at 05:23