简体   繁体   中英

ActiveRecord undefined method `has_key?' for nil:NilClass error

I have a fairly simple forms-over-data Rails app that calls a remote MySql 5.5 db. Using Rails 3.2.21, Ruby 1.9.3.

One of the pages in the app is throwing the following error:

NoMethodError in GvpController#input
   undefined method `has_key?' for nil:NilClass
   app/controllers/gvp_controller.rb:9:in `input'

Here is the offending code from the controller:

class GvpController < ApplicationController
  def input
    # irrelevant stuff
    @list =  Vendor.gvp_vendor_names.map { |x| x.vendor_name }
    # more irrelevant stuff
  end      
  # other irrelevant methods
end

I'm assuming the call to gvp_vendor_names is returning nil.

Here is the Vendor model class:

class Vendor < ActiveRecord::Base
  establish_connection :vendor_sql
  self.table_name = 'reporting_dw.vp_vendor_mapping'
  scope :gvp_vendor_names, -> {
    select('reporting_dw.vp_vendor_mapping.vendor_name')}
end

I have searched other posts with this error message and so far haven't found one that seems relevant. I am not overriding the initialize method (one possible cause) and I think the syntax is correct (another).

As an additional wrinkle, I am using vagrant for development, so I thought perhaps I'm not successfully communicating with the database from the vagrant box - maybe an ssh or permissions issue. To test it, I opened an ssh session on the vagrant box, successfully connected with the db via command line ran a select statement and lo and behold, get the full list of results I was expecting. I also tried it with mysql workbench via ssh and had no problems. So, it seems I can communicate remotely with the db, execute queries against it, have the proper permissions etc.

Does anyone have any suggestions as to what the problem might be?

I assume that you haven't any value on your DB tables. That's why the issue arise in controller action block during you call gvp_vendor_names mapped value vendor_name

You should handle this type of case by checking the object value rather than accessing firstclass

GvpController < ApplicationController
  def input
    # irrelevant stuff
    @list =  Vendor.gvp_vendor_names.map { |x| x.vendor_name if x.present?}
    # more irrelevant stuff
  end      
  # other irrelevant methods
end

In this way you need to compact the nil value. So use this finally if you want to handle the scenario from controller:

class GvpController < ApplicationController
  def input
    # irrelevant stuff
    @list =  Vendor.gvp_vendor_names.map { |x| x.vendor_name if x.present?}.compact
    # more irrelevant stuff
  end      
  # other irrelevant methods
end

The real problem may just be that I'm a Rails/ActiveRecord n00b. After a little more experimentation, I found the following changes corrected the error.

In the model I added attr_accessible and then used engineersmnky's suggestion of using a method rather than scope, as follows:

class Vendor < ActiveRecord::Base
  establish_connection :vendor_sql 
  attr_accessible :vendor_name
  self.table_name = 'reporting_dw.vp_vendor_mapping'

  def self.gvp_vendor_names
    pluck(:vendor_name).sort
  end
end

Then in the controller:

class GvpController < ApplicationController
  def input
    #irrelevant stuff
    @list = Vendor.gvp_vendor_names 
    #irrelevant stuff
  end
end

That fixed it. Thank you everyone for the suggestions!

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM