user2469227
user2469227

Reputation:

Why are undeclared @variables nil in html.erb and not a NameError

If an html.erb file is rendered without variables assigned in a controller (e.g. @user = params["user_name"] ) then why does it view @user as nil instead of throwing a NameError: undefined local variable.

For Example:

<%= render partial: "greeting", locals: { user: @user } if @user %>

This will render the greeting if a controller passes it a @user, but if the page is rendered for the first time and the user hasn't entered their username yet the greeting will simply not be there, instead of causing an error. It seems to me that @user would never be declared in the local scope the html.erb is executing in, so it should cause the error.

What's happening here? Perhaps the @ is somehow preprocessed to mean treat the variable as a symbol and use that as the key in a params hash and return the result?

Upvotes: 3

Views: 504

Answers (2)

J&#246;rg W Mittag
J&#246;rg W Mittag

Reputation: 369468

then why does it view @user as nil instead of throwing a NameError: undefined local variable.

Well, it's not a local variable, it's an instance variable.

But even local variables behave the same way:

if false
  local_var = 42 # needed so Ruby knows `local_var` isn't a method call
end

local_var
# => nil

@instance_variable
# => nil

$global_variable
# => nil

But strangely:

Constant
# NameError: uninitialized constant Constant

@@class_variable
# NameError: uninitialized class variable @@class_variable in Object

Upvotes: 0

August
August

Reputation: 12558

Uninitialized instance variables (@...) evaluate to nil. You can still check if an instance variable has been assigned (including assignment to nil) by using the defined? method:

[1] pry(main)> defined? @test
=> nil
[2] pry(main)> @test = nil
=> nil
[3] pry(main)> defined? @test
=> "instance-variable"

Upvotes: 5

Related Questions