nonsequiter
nonsequiter

Reputation: 741

Rails throwing undefined method `[]' for nil:NilClass even thought everything is working

I have a view at the route 'memorisation' and it has an file import for CSV file-types. When I run the import, all of the changes seem to be working fine for all 139 records. However, I am still getting an error.

NoMethodError in MemorisationController#import
undefined method `[]' for nil:NilClass

This is my controller method:

  def import
    require 'csv'
    all_targets = MemoTarget.order(:id).includes(:memo_level).map do |t|
      {
      :id => t.id,
      :target => t.target_number,
      :level => t.memo_level.level_number
      }
    end
    CSV.foreach(params[:file].path, headers: true) do |row|
      the_target = MemoTest.create do |test|
        test.student_id = row["student_id"]
        test.teacher_id = session[:user_id]
        test.memo_target_id = all_targets.find {|t| t[:level] == row["memo_level"].to_i and t[:target] == row["memo_target"].to_i}[:id]
        test.result = true
      end
    end
    redirect_to '/memorisation', notice: 'Student memorisation current targets imported'
  end

The line test.memo_target_id = all_targets.find {|t| t[:level] == row["memo_level"].to_i and t[:target] == row["memo_target"].to_i}[:id] is throwing the error.

In my server log, all the expected changes are being made as shown by the SQL COMMITs. After the commits, the controller should redirect back to the memorisation page.

   ...
   (0.7ms)  COMMIT
   (0.3ms)  BEGIN
  SQL (0.5ms)  INSERT INTO "memo_tests" ("student_id", "teacher_id", "memo_target_id", "result", "created_at", "updated_at") VALUES ($1, $2, $3, $4, $5, $6) RETURNING "id"  [["student_id", 139], ["teacher_id", 1], ["memo_target_id", 30], ["result", "t"], ["created_at", "2015-09-13 08:08:05.205922"], ["updated_at", "2015-09-13 08:08:05.205922"]]
   (0.6ms)  COMMIT
Completed 500 Internal Server Error in 6145ms

NoMethodError (undefined method `[]' for nil:NilClass):
  app/controllers/memorisation_controller.rb:33:in `block (2 levels) in import'
  app/controllers/memorisation_controller.rb:30:in `block in import'
  app/controllers/memorisation_controller.rb:29:in `import'


  Rendered /Users/Javu/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_source.erb (135.6ms)
  Rendered /Users/Javu/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_trace.html.erb (69.8ms)
  Rendered /Users/Javu/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/_request_and_response.html.erb (13.1ms)
  Rendered /Users/Javu/.rbenv/versions/2.2.0/lib/ruby/gems/2.2.0/gems/actionpack-4.2.0/lib/action_dispatch/middleware/templates/rescues/diagnostics.html.erb within rescues/layout (270.0ms)
Cannot render console with content type multipart/form-dataAllowed content types: [#<Mime::Type:0x007fd4d2cd4c28 @synonyms=["application/xhtml+xml"], @symbol=:html, @string="text/html">, #<Mime::Type:0x007fd4d2cd4868 @synonyms=[], @symbol=:text, @string="text/plain">, #<Mime::Type:0x007fd4d2ccc2a8 @synonyms=[], @symbol=:url_encoded_form, @string="application/x-www-form-urlencoded">]

I've looked through it with byebug to see if there was any problem with the import or the 139th record, but everything seems to be fine.

I want to know what's causing this errot and how to rectify it.

Upvotes: 1

Views: 1065

Answers (1)

Vishnu Atrai
Vishnu Atrai

Reputation: 2368

row is nil in your CSV file that is why you are getting this error, try below code it will work.

def import
  require 'csv'
  all_targets = MemoTarget.order(:id).includes(:memo_level).map do |t|
    {
    :id => t.id,
    :target => t.target_number,
    :level => t.memo_level.level_number
    }
  end
  CSV.foreach(params[:file].path, headers: true) do |row|
    next if row.all?(&:blank?)
    the_target = MemoTest.create do |test|
      test.student_id = row["student_id"]
      test.teacher_id = session[:user_id]
      test.memo_target_id = all_targets.find {|t| t[:level] == row["memo_level"].to_i and t[:target] == row["memo_target"].to_i}[:id]
      test.result = true
    end
  end
  redirect_to '/memorisation', notice: 'Student memorisation current targets imported'
end

Upvotes: 3

Related Questions