Ruby Undefined method downcase

18,945

When you see "undefined method ... for nil:NilClass" it means you have a nil value you're trying to call the method on.

In this case, something like data['name'] is not defined.

To make this more bullet-proof:

data['name'].to_s.downcase.gsub(/\s+/, '')

This converts everything to string to start with. nil.to_s is an empty string by default, so it's safe.

Share:
18,945
charliexx
Author by

charliexx

Updated on July 09, 2022

Comments

  • charliexx
    charliexx almost 2 years

    I'm getting an exception in the following piece of code. Can someone please tell me what I'm doing wrong, and how I can prevent it?

    def self.find_by_data(data = {})
                where(name_canonical: data['name'].downcase.gsub(/\s+/, ''),
                      fuel:           data['fuel'],
                      trim_canonical: data['trim'].downcase.gsub(/\s+/, ''),
                      year:           data['year']).first
            end
    

    Exception:

    /Users/charlie/Documents/WIP/projectx/ar_models.rb:35:in `find_by_data': undefined method `downcase' for nil:NilClass (NoMethodError)ooooooooooooooooooooooooo| ETA:   0:00:00
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-4.0.0/lib/active_record/relation/delegation.rb:36:in `block in find_by_data'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-4.0.0/lib/active_record/associations/collection_proxy.rb:845:in `block in scoping'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-4.0.0/lib/active_record/relation.rb:270:in `scoping'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-4.0.0/lib/active_record/associations/collection_proxy.rb:845:in `scoping'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-4.0.0/lib/active_record/relation/delegation.rb:36:in `find_by_data'
        from /Users/charlie/Documents/WIP/projectx/ar_models.rb:132:in `create_or_assign_existing'
        from /Users/charlie/Documents/WIP/projectx/app.rb:230:in `block (2 levels) in work'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/activerecord-4.0.0/lib/active_record/connection_adapters/abstract/connection_pool.rb:294:in `with_connection'
        from /Users/charlie/Documents/WIP/projectx/app.rb:80:in `block in work'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:319:in `call'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:319:in `call_with_index'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:179:in `block (3 levels) in work_in_threads'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:326:in `with_instrumentation'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:177:in `block (2 levels) in work_in_threads'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:171:in `loop'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:171:in `block in work_in_threads'
        from /Users/charlie/.rvm/gems/ruby-2.0.0-p0/gems/parallel-0.6.3/lib/parallel.rb:62:in `block (2 levels) in in_threads'
    
    • Arup Rakshit
      Arup Rakshit over 10 years
      we don't know what your hash data contain.. But it is very clear that either data['name'] or data['trim'] contains nil. Check the same
  • tadman
    tadman over 10 years
    == nil is supremely ugly. A better alternative is .nil? but only if that value might be false. Even better in this case is: data['name'] ? data['name'].downcase.gsub(...) : ''
  • konsolebox
    konsolebox over 10 years
    @tadman Yet it's a solution. A better one please? Do we have to go after has_key?? But wouldn't nil still be possible for that and that we have to check again?
  • tadman
    tadman over 10 years
    I've posted my own take that involves to_s which forces the value to a string, regardless of if it's nil or not. 99% of the time x == nil can be replaced with !x or in this case, simply reversing the ternary.
  • konsolebox
    konsolebox over 10 years
    Now that's ugly for me.
  • tadman
    tadman over 10 years
    It's the same thing you have, minus == nil, reversing the logic.
  • konsolebox
    konsolebox over 10 years
    As you said, not having nil could still apply to false. Also a to_s method is a dirty hack.