Ruby `respond_to?` returns true when actually false

421 views Asked by At

I have a fairly simple null object class:

class NullObject
  def present?
    false
  end
end

class NullVal < NullObject
  attr_accessor :field

  delegate(
    :allow_edits,
    :box,
    :content,
    :id,
    :locked_for?,
    :number,
    :page_num,
    :page_seq,
    :position_css,
    :position_css_hash,
    :required,
    :required?,
    :size_css,
    :size_css_hash,
    :type,
    to: :field,
  )

  def initialize(field:)
    self.field = field
  end
end

and I'm using it in a rails partial cache key:

- cache [vals] do
  -# render stuff

I'm seeing the following error:

NoMethodError - undefined method `cache_key' for #<NullVal:0x000000080ceb78>:
  /home/fletch/.rvm/rubies/ruby-2.1.6/lib/ruby/2.1.0/delegate.rb:343:in `block in delegating_block'
  activesupport (4.2.2) lib/active_support/cache.rb:94:in `retrieve_cache_key'
  activesupport (4.2.2) lib/active_support/cache.rb:95:in `block in retrieve_cache_key'
  activesupport (4.2.2) lib/active_support/cache.rb:95:in `retrieve_cache_key'
  activesupport (4.2.2) lib/active_support/cache.rb:95:in `block in retrieve_cache_key'
  activesupport (4.2.2) lib/active_support/cache.rb:95:in `retrieve_cache_key'
  activesupport (4.2.2) lib/active_support/cache.rb:87:in `expand_cache_key'
  actionpack (4.2.2) lib/action_controller/caching/fragments.rb:22:in `fragment_cache_key'
  actionpack (4.2.2) lib/action_controller/caching/fragments.rb:43:in `read_fragment'
  actionview (4.2.2) lib/action_view/helpers/cache_helper.rb:183:in `read_fragment_for'
  actionview (4.2.2) lib/action_view/helpers/cache_helper.rb:179:in `fragment_for'
  actionview (4.2.2) lib/action_view/helpers/cache_helper.rb:115:in `cache'
  app/views/docs/_doc.html.haml:13:in `block in _app_views_docs__doc_html_haml___3057171325955977412_79957620'

The relevant line of code from activesupport is:

when key.respond_to?(:cache_key) then key.cache_key

If I toss a puts in there, it returns true for key.respond_to?(:cache_key), and it is, in fact an instance of NullVal. If I instantiate a NullVal in the console it returns false for the same. What is happening here? method(:respond_to?).source_location returns nil for both...

1

There are 1 answers

0
lobati On

Okay, figured out the problem. I have a ValDecorator class that I use to wrap the NullVal. When I was printing it to the console it was showing as #<NullVal:0x0000000a1f3ab0 @field=...>, but it was in fact the decorator. I'm using DelegateClass:

class ValDecorator < DelegateClass(Val)
end

Since it's using Val for respond_to? and actually trying to call it on NullVal, it throws a surprising error. Will have to think about the implementation of this a little more.