Welcome to the Treehouse Community

Want to collaborate on code errors? Have bugs you need feedback on? Looking for an extra set of eyes on your latest project? Get support with fellow developers, designers, and programmers of all backgrounds and skill levels here with the Treehouse Community! While you're at it, check out some resources Treehouse students have shared here.

Looking to learn something new?

Treehouse offers a seven day free trial for new students. Get access to thousands of hours of content and join thousands of Treehouse students and alumni in the community today.

Start your free trial

Ruby

undefined local variable for main :Object in Ruby program

Attached is a simple, silly "budget" program to test out some of what I've learned so far. It's needlessly complicated, as I can run this program with just an if statement, but I wanted to work on my understanding of classes. When I run it, it accepts and stores my input, but then returns an error about the last line saying "beginnerbudget.rb:19:in <main>': undefined local variable or methodchecking_amount' for main:Object (NameError)". How could this be, since the variable checking_amount is specified as an attr_accessor? Shouldn't the variable be available, since it's both an attr_accessor and also defined outside of the method in the first place?

I know I could specify an amount as an argument when I call the method but I want this to be based on user input, rather than a specified amount given when I call the method and run it.

class Beginnerbudget
  attr_accessor :checking_amount
  puts "How much money do you have in your checking account?"
  checking_amount = gets.chomp.to_i

 def rate_savings(checking_amount)
    @checking_amount = checking_amount
    if checking_amount >= 501
        puts "You have $#{checking_amount} in your account. Keep up the good work!"
    elsif checking_amount <= 500 && checking_amount >= 101
        puts "You only have $#{checking_amount} in your account. Try and save a little more this month."
    else checking_amount < 100 
        puts "Yikes, you only have $#{checking_amount} in your account! Sell a kidney quick!"
    end
  end
end

beginner_budget = Beginnerbudget.new
beginner_budget.rate_savings(checking_amount)

2 Answers

Taylor Boudreau
Taylor Boudreau
7,285 Points

Hi there Heather,

Two things I see here. When you create the initialize method, you will want to update the checking_amount variable to be defined as an instance variable when you get the user input. (@checking_amount = gets.chomp.to_i)

Also when instantiating the class, you won't have to call the initialize method as it's automatically run when you create the instance of Beginnerbudget. If you remove beginner_budget.initialize as well you should see that run properly. This is explained in greater detail (http://www.rubyist.net/~slagell/ruby/objinitialization.html):

"Whenever Ruby creates a new object, it looks for a method named initialize and executes it. So one simple thing we can do is use an initialize method to put default values into all the instance variables, so the inspect method will have something to say."

My code:

class Beginnerbudget 
    attr_accessor :checking_amount 

    def initialize 
        puts "How much money do you have in your checking account?" 
        @checking_amount = gets.chomp.to_i 
    end 

    def rate_savings 
        if checking_amount >= 501 
            puts "You have $#{checking_amount} in your account. Keep up the good work!" 
        elsif checking_amount <= 500 && checking_amount >= 101 
            puts "You only have $#{checking_amount} in your account. Try and save a little more this month." 
        else checking_amount < 100 
            puts "Yikes, you only have $#{checking_amount} in your account! Sell a kidney quick!"
        end  
    end 
end 

beginner_budget = Beginnerbudget.new 
beginner_budget.rate_savings

Thanks very much!

Taylor Boudreau
Taylor Boudreau
7,285 Points

Hi there Heather!

It looks like you may be running into issues because where you're passing the checking_amount a value from user input, you're not using setting checking_amount as an instance variable. One way we're taught to fix this is by moving some of your code that's run when the class is instantiated into an initialize method. For your program, this may look something like this:

def initialize
    puts "How much money do you have in your checking account?"
    @checking_amount = gets.chomp.to_i
  end

The @checking_amount gives you access to this variable when you call your rate_savings methods, but this needs to be done when the variable is first set, and only once. This also means you don't need to pass checking_amount as an argument into your rate_savings method, so it'd need to look something like this:

def rate_savings
  if checking_amount >= 501

I love the program and I hope this helps!

Taylor

Hi Taylor, thanks for your comment! I implemented the changes you recommended, and I got another error, saying "beginnerbudget.rb:22:in <main>': private methodinitialize' called for #<Beginnerbudget:0x608da8> (NoMethodError)". Why would this be a private method? How can I fix it?

class Beginnerbudget
  attr_accessor :checking_amount

  def initialize
    puts "How much money do you have in your checking account?"
    @checking_amount = checking_amount
    checking_amount = gets.chomp.to_i
  end

 def rate_savings
    if checking_amount >= 501
        puts "You have $#{checking_amount} in your account. Keep up the good work!"
    elsif checking_amount <= 500 && checking_amount >= 101
        puts "You only have $#{checking_amount} in your account. Try and save a little more this month."
    else checking_amount < 100 
        puts "Yikes, you only have $#{checking_amount} in your account! Sell a kidney quick!"
    end
  end
end

beginner_budget = Beginnerbudget.new
beginner_budget.initialize
beginner_budget.rate_savings