Bruno Velasco
Bruno Velasco

Reputation: 135

Rails ActiveSupport::Concern and method evaluation

I have this application which uses Devise with current_user helper. When I create a module, current_user becomes nil after I mention an attribution to it even though it never happens.

class PagesController < ApplicationController
  include ModuleTest

  def index
    a_test_method
  end
end

And the ModuleTest:

module ModuleTest
  extend ActiveSupport::Concern

  def a_test_method
    puts "(BEFORE)===========> #{current_user.inspect}"
    current_user = nil if false
    puts "(AFTER) ===========> #{current_user.inspect}"
  end
 end

Output:

(BEFORE)===========> #<User id: 1>
(AFTER) ===========> nil

However, if I delete/comment out this line # current_user = nil if false, current_user remains valid:

(BEFORE)===========> #<User id: 1>
(AFTER) ===========> #<User id: 1>

Would this be related to lazy evaluation somewhat?

EDIT

The whole problem relies on how Ruby defines variables when a statement is not evaluated:

2.3.4 (main):0 > defined? this_never_seen_variable_before
=> nil
2.3.4 (main):0 > this_never_seen_variable_before = "value" if false
=> nil
2.3.4 (main):0 > defined? this_never_seen_variable_before
=> "local-variable"
2.3.4 (main):0 >
2.3.4 (main):0 > this_never_seen_variable_before_2
   NameError: undefined local variable or method `this_never_seen_variable_before_2' for main:Object
from (pry):119:in `<main>'
2.3.4 (main):0 > this_never_seen_variable_before_2 = "value" if false
=> nil
2.3.4 (main):0 > this_never_seen_variable_before_2
=> nil
2.3.4 (main):0 >

How does this work underneath?

Upvotes: 2

Views: 357

Answers (1)

Aetherus
Aetherus

Reputation: 8888

  1. current_user is a helper method provided by Devise, not a local variable.

  2. There is no such helper method named current_user=. You can prove this by changing current_user = nil to self.current_user = nil and see it crash. But this is irrelevant to your issue.

So the result is, you defined a local variable current_user between the 2 puts, which shadows the helper method with the same name.

The weird thing is, although current_user = nil is not executed because of the if false, the local variable still gets defined, and its value is implicitly set to nil. This is why your second puts shows nil. Even if you change your current_user = nil to current_user = :someone, your second puts should still show nil.

Upvotes: 2

Related Questions