3

In debugging console, while app running (using binding.pry to interrupt it), I can see that my variable Rails.configuration.hardcoded_current_user_key is set:

pry(#<TasksController>)> Rails.configuration.hardcoded_current_user_key
=> "dev"

But it doesn't appear to be defined:

pry(#<TasksController>)> defined?(Rails.configuration.hardcoded_current_user_key)
=> nil

Yet it works fine to store and test its value:

pry(#<TasksController>)> tempVar = Rails.configuration.hardcoded_current_user_key
=> "dev"
pry(#<TasksController>)> defined?(tempVar)
=> "local-variable"

What is going on?

2 Answers 2

4

This is because Rails config implements respond_to? but not respond_to_missing?, and defined? only recognizes respond_to_missing?:

class X
  def respond_to?(name, include_all = false)
    name == :another_secret || super
  end

  private

  def method_missing(name, *args, &block)
    case name
    when :super_secret
      'Bingo!'
    when :another_secret
      'Nope.'
    else
      super
    end
  end

  def respond_to_missing?(name, include_all = false)
    name == :super_secret || super
  end
end

x = X.new
puts x.super_secret          # => Bingo!
p defined?(x.super_secret)   # => "method"
puts x.another_secret        # => Nope.
p defined?(x.another_secret) # => nil

It's recommended to implement respond_to_missing? along with method_missing, I too wonder why Rails did it that way.

Sign up to request clarification or add additional context in comments.

1 Comment

Thanks, I'm struggling to wrap my brain around this!
0

You shouldn't be using defined? on anything but the "stub" of that, or in other words, merely this:

defined?(Rails)

Anything beyond that is highly unusual to see, and I'm not even sure it's valid.

defined? is not a method, but a construct that tests if the following thing is defined as a variable, constant or method, among other things. It won't evaluate your code, it will just test it as-is. This means method calls don't happen, and as such, can't be chained.

If you want to test that something is assigned, then you should use this:

Rails.configuration.hardcoded_current_user_key.nil?

4 Comments

It is valid; for example: defined? Rails, defined? Rails.configuration, defined? Rails.configuration.time_zone, defined? String.new.length, and String.new.pancakes are all fine and yield the expected value. defined? Rails.configuration.custom_env_thing says nil even though Rails.configuration.custom_env_thing works. I wonder if there is some method_missing? trickery going on.
@muistooshort Could be the case, where it's not actually a method. I've seen some Rails proxy classes that are frustratingly transparent.
But if Rails.configuration.hardcoded_current_user_key can be evaluated, doesn't that mean it is a variable, constant or method? Is there no way to check if a given dot-resolved thing (I'm not even sure what to call these) exists? .nil? doesn't cut it, because I might define a and set it to nil, but never define b... there must be some way to tell after the fact that a is defined and assigned but b is not without crashing rails!
The defined?(...) method is intended for constants where referencing them would cause an exception. Normally you test variables versus nil or whatever expected result using regular logic. Try to avoid using defined?(...) unless you're testing for the presence of a module, class or constant.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.