'Only execute code in erb if variable exists?

Ruby newbie here who just started using Ruby with .erb templates and I'm having a problem with the code. I have a hangman game that's passing variables from the .rb file to the .erb file and everything was working fine until I tried to check it on initial load (no variables present) and it threw errors. So I figured I'd use defined? with an if statement to check if the variable exists and then execute the code if it does and ignore if doesn't. It works fine when I use:

<% if defined?bad_guesses %>
    <%= bad_guesses %>
<% end %>

But the information I need is an array and when I try to use an .each or .times statement like this:

<% if defined?bad_guesses %>
  <% bad_guesses.each do |i| %>
    <%= i %>
  <% end %>
<% end %>

I get:

NoMethodError at /

undefined method `each' for nil:NilClass

C:/Projects/hangman/views/index.erb in block in singleton class

  1. <% bad_guesses.each do |i| %> hangman.rb in block in

  2. erb :index, :locals => {:game_status => game_status, :bad_guesses => bad_guesses, :good_guesses => good_guesses, :word => word}

Any suggestions appreciated.

Also, is this even the proper way to do this? When you make an .erb template that uses variables passed in from a class in your .rb file, how do you ignore it until it exists to the template?

Passing variables using:

get '/' do
    if params['make'] != nil
        make = params['make'].to_i
        game_status, bad_guesses, good_guesses, word = Hangman.get_word(make)
    elsif params['guess'] != nil
        guess = params['guess'].to_s
        game_status, bad_guesses, good_guesses, word = Hangman.check_guess(guess)
    end
  erb :index, :locals => {:game_status => game_status, :bad_guesses => bad_guesses, :good_guesses => good_guesses, :word => word}
end


Solution 1:[1]

Looking at this:

<% if defined?bad_guesses %>
  <% bad_guesses.each do |i| %>
    <%= i %>
  <% end %>
<% end %>

a few points:

  1. defined?a is bad style; use defined?(bad_guesses) or defined? bad_guesses instead.
  2. defined? checks if it's defined, so if you say foo = nil; defined? foo it will be true.

You could alternatively use this:

defined?(bad_guesses) && bad_guesses

On the other hand, undefined instance variables are nil by default:

# it shows undefined
defined? @non_existing_var

# but you can still check if it's truthy:
puts "found" if @non_existing_var
# it won't print anything

Similar to instance variables in this regard are hashes. The default value of an unknown key is nil.

The problem with instance variables is they are not scoped to the partial. Instead, I recommend sending your local variables as a nested hash:

locals: { data: { foo: "bar" } }

Then you can safely check for values which may not exist:

if data[:foo]
  # this runs
elsif data[:non_existent]
  # this doesnt run
end

Solution 2:[2]

For my purposes, the following syntax worked:

<% if some_var %>
  <%= some_var %> 
<% end %>

This block is rendered if some_var is not nil.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 max pleaner
Solution 2