FAQ: A Night at the Movies - Nice Work!

This community-built FAQ covers the “Nice Work!” exercise from the lesson “A Night at the Movies”.

Paths and Courses
This exercise can be found in the following Codecademy content:

Learn Ruby

FAQs on the exercise Nice Work!

There are currently no frequently asked questions associated with this exercise – that’s where you come in! You can contribute to this section by offering your own questions, answers, or clarifications on this exercise. Ask or answer a question by clicking reply (reply) below.

If you’ve had an “aha” moment about the concepts, formatting, syntax, or anything else with this exercise, consider sharing those insights! Teaching others and answering their questions is one of the best ways to learn and stay sharp.

Join the Discussion. Help a fellow learner on their journey.

Ask or answer a question about this exercise by clicking reply (reply) below!

Agree with a comment or answer? Like (like) to up-vote the contribution!

Need broader help or resources? Head here.

Looking for motivation to keep learning? Join our wider discussions.

Learn more about how to use this guide.

Found a bug? Report it!

Have a question about your account or billing? Reach out to our customer support team!

None of the above? Find out where to ask other questions here!

I added a menu which included an exit because I wrapped the whole thing in a loop for more fun. I also used .downcase! on choice just in case.
Fun exercise. :grinning:

Hi I’m trying to add a block of code to this movie library ruby project that picks a movie at radom but keep getting this error: undefined method `sample’ for nil:NilClass

Code below. Bold area is the code that generates the error.

movies = {
memento: 3,
toy_story: 3,
gladiator: 4,
avengers: 4
}

puts “What would you like to do?”

choice = gets.chomp

case choice

when “add”
puts “Movie to be added?”
title = gets.chomp
if movies[title.to_sym].nil?
puts “Add a rating (0 to 4)”
rating = gets.chomp
movies[title.to_sym] = rating.to_i
puts “#{title.capitalize}” " has been added with a rating of" " #{rating}"
else
puts “#{title.capitalize}” " already exists. It has a rating of"" #{rating}."
end

when "update"

puts “Which movie do you want to update?”
title = gets.chomp
if movies[title.intern].nil?
puts “Sorry,” " #{title.capitalize}" " wasn’t found!"
else
puts “Please add a new rating (0 to 4) for” " #{title.capitalize}."
rating = gets.chomp
movies[title.intern] = rating.to_i
puts “#{title.capitalize}” " has been updated with a new rating of" " #{rating}."
end

when “display”
movies.each do |title, rating|
puts “#{title}: #{rating}”
end

when “delete”
puts “Which movie do you want to delete?”
title = gets.chomp
if movies[title.intern].nil?
puts “Sorry, that movie wasn’t found!”
else
movies.delete(title.intern)
puts “#{title.capitalize}” " deleted!"
end

when "random"
** if movies.nil?**
** puts “Nothing to see here!”**
** else**
** puts “#{title.sample}: #{rating}”**
** end**

else
puts “Error!”
end

Is sample defined anywhere?

1 Like

What concept and/or syntax do I need to learn to make this exercise restart from the beginning where it asks for which of the 4 options user wants, after those conditions are met?

For example, if I successfully add a new movie and rating pairing to the hash, how do i get it so it goes back to the start, I can type display instead, and see my new entry? or with delete, seeing the new hash table after deleting a pairing. I tried putting the entire case inside a loop/end, but it goes on forever with no breaks.

I found an old thread that goes into rather more detail than what you ask for here, but it may offer some hints…

https://discuss.codecademy.com/t/7-update/53870/6

How were you able to get the entire thing to loop?

The member may no longer be checking in to the forums, so let’s have a look at some options…

The first option would be to make the code a loop body.

while run

  puts "What would you like to do?"
  puts "-- Type 'add' to add a movie."
  puts "-- Type 'update' to update a movie."
  puts "-- Type 'display' to display all movies."
  puts "-- Type 'delete' to delete a movie."
  puts "-- Type 'quit' to terminate the program."
  # ...
end

Note that we have added an option to the menu, and will need to write a conditional to test for that input.

    when 'quit'
        run = false

Be sure to declare the movies hash outside of the loop when initializing the program. We could also declare a running variable to accommodate the loop.

run = true

So the loop will continue as long as that variable is true. Once we set it to false the loop should terminate.

This should be easily adapted to your existing code.


Another approach would be to use standalone functions and use the loop as a traffic controller.

def add
  puts "What movie do you want to add?"
  title = gets.chomp
  if movies[title.to_sym].nil?
    puts "What's the rating? (Type a number 0 to 4.)"
    rating = gets.chomp
    movies[title.to_sym] = rating.to_i
    puts "#{title} has been added with a rating of #{rating}."
  else
    puts "That movie already exists! Its rating is #{movies[title.to_sym]}."
  end
end

and so on. The loop would contain only the menu and a case statement to call up each function, as ordered.

    when 'add' then add()

That won’t make it any better, but it will shorten the loop body and make it easier to read.

2 Likes

This is a version that runs until you quit.

A Night at the Movies
def add
  print "Movie title: "
  title = gets.chomp
  if $movies[title.to_sym].nil?
    print "Movie rating: "
    rating = gets.chomp
    $movies[title.to_sym] = rating.to_i
    puts "#{title} added with rating #{rating}."
  else
    puts "#{title} exists with rating #{$movies[title.to_sym]}."
  end
end

def update
  print "Movie title: "
  title = gets.chomp
  if $movies[title.to_sym].nil?
    puts "#{title} not in hash."
  else
    print "Movie rating: "
    rating = gets.chomp
    $movies[title.to_sym] = rating.to_i
    puts "#{title} updated with rating #{rating}."
  end
end

def display
  $movies.each { |movie, rating| puts "#{movie}: #{rating}"}
end

def delete
  print "Which movie do you wish to delete?"
  title = gets.chomp
  if $movies[title.intern].nil?
    puts "The movie #{title} is not in the database!"
  else 
    $movies.delete(title.intern)
    puts "The movie #{title} a has been removed from the database."
    display()
  end
end

def menu  
  "
What would you like to do?
-- Type 'add' to add a movie.
-- Type 'update' to update a movie.
-- Type 'display' to display all movies.
-- Type 'delete' to delete a movie.
-- Type 'quit' to terminate the program.

"
end

$movies = {
  Crash: 4,
  Babel: 4,
  "A Night to Remember": 2
}

while true
  puts menu
  print "your command: "
  choice = gets.chomp
  case choice
    when "add" then add()
    when "display" then display()
    when "update" then update()
    when "delete" then delete()
    when "quit" then break
  else
    puts "Error!"
  end
end
puts "Bye!"

Because we are using a global for movies, note the change in the variable name used.

Play with it on REPL.IT

Feel free to make a FORK of this one and continue building upon what we have here. Ping us with any further improvements.

1 Like

Hi guys !

As it shows on repl.it, I’m trying to create methods to organize my code and practicing ! For now, here my code :

movies = {
  inception: 2.5,
  snatch: 3,
  endgame: 4
}

def add
  puts "What is the name of the movie ?"
  title = gets.chomp
  if movies[title.to_sym].nil?
    puts "What is the rating of #{title} ? (0 to 5)"
    rating = gets.chomp
    movies[title.to_sym] = rating.to_i
    puts "#{title} added with a rating of #{rating} !"
  else puts "#{title} already exists with a rating of #{rating} !"
  end
end

puts add

When I’m running the code, here what is displayed on the console :

What is the name of the movie ?
avatar
undefined local variable or method `movies' for #<Context:0x9896e4>

Could you explain me what’s wrong with that ? Other question, I saw on the code from mtf a $ used before the variable “movies” I can’t figure it out its functionnality…

Thanks for your help !

Gobal Variables

2 Likes

Thanks mtf, I found out it was actually a global variable few minutes after I asked the question :slight_smile:

Returning to my first question, do you know why I have this error and how can I fix it ? I’m looking for a solution for hours now haha

1 Like

Add the $ to the movies variable so the method can access it for writing.

1 Like

Thank you mtf !

So when I’m using a method, I must add $ everytime to give the access to the variable, isn’t it ?

There is something else I can’t figure it out about this code :

def add
  puts "What is the name of the movie ?"
  title = gets.chomp
  if $movies[title.to_sym].nil?
    puts "What is the rating of #{title} ? (0 to 5)"
    rating = gets.chomp
    $movies[title.to_sym] = rating.to_i
    puts "#{title} added with a rating of #{$movies[title.to_sym]} !"
  else puts "#{title} already exists with a rating of #{$movies[title.to_sym]} !"
  end
end

Why can’t I use this code "#{title} already exists with a rating of #{rating} !" to display the rating ? I can’t understand what this code does #{$movies[title.to_sym]}

Thank you so much for your patience !

The $ declares a variable as writable from any scope. The best practices guide would be where to look for pro’s and con’s.

Ruby kinda likes variables to be defined the same way as methods.

def pi
  Math::PI
end

Without reading up (in this time frame) how we can apply this same framework to our $movies object I can only guess we need to classify it so we can protect it better. Something to add to the bewilderment pile.

1 Like

Hi guys !

I’m trying to improve this program and I’m stucked on something. Here my code :

def add
  puts "What is the name of the movie ?"
  title = gets.chomp
  if $movies[title.to_sym].nil?
    puts "What is the rating of #{title} ? (0 to 5)"
    rating = gets.chomp
    $movies[title.to_sym] = rating.to_i
    if rating.to_i == 1 || 2 || 3 || 4 || 5
      puts "#{title} added with a rating of #{$movies[title.to_sym]} !"
    else
      puts "This value is not allowed : please try again !"
      puts add
    end
  else puts "#{title} already exists with a rating of #{$movies[title.to_sym]} !"
  end
  puts restart
end

I don’t know how to write correctly this line if rating.to_i == 1 || 2 || 3 || 4 || 5 how could I fix that ?

Thanks for your help !

Short-circuits on the first truthy, namely, 1.
Consider switching around that line and the one above it. Test, then assign, not the other way around.

The test is a range.

  if (1..5).include? rating.to_i 
    $movies[title.to_sym] = rating.to_i
  else
3 Likes

Thank you so much for your help mtf ! It works now :slight_smile: I’ll keep your advice in my mind !

I think I’m now done with this program, any comments about my code ? Improvements or whatever ?

$movies = {
  inception: 2.5,
  snatch: 3,
  endgame: 4
}

def add
  puts "What is the name of the movie ?"
  title = gets.chomp
  if $movies[title.to_sym].nil?
    puts "What is the rating of #{title} ? (0 to 5)"
    rating = gets.chomp
    if (1..5).include? rating.to_i
      $movies[title.to_sym] = rating.to_i
      puts "#{title} added with a rating of #{$movies[title.to_sym]} !"
    else
      puts "This value is not allowed : please try again !"
      puts add
    end
  else puts "#{title} already exists with a rating of #{$movies[title.to_sym]} !"
  end
  puts restart
end

def update
  puts "Which movie rating would you like to update ?"
  title = gets.chomp
  if $movies[title.to_sym].nil?
    puts "#{title} doesn't exist in our database !"
  else puts "Which rating would you like to attribute to #{title} ? (0 to 5)"
    rating = gets.chomp
    if (1..5).include? rating.to_i
      $movies[title.to_sym] = rating.to_i
      puts "The rating of #{title} changed to the value #{rating} !"
    else
      puts "This value is not allowed : please try again !"
      puts update
    end
  end
  puts restart
end

def display
  puts "Here the currently database : \n"
  $movies.each do |movie, rating| puts "#{movie} : #{rating}"
  end
  puts restart
end

def delete
  puts "Which movie would you like to delete from our database ?"
  title = gets.chomp
  if $movies[title.to_sym].nil?
    puts "#{title} doesn't exist in our database !"
  else $movies.delete(title.to_sym)
    puts "#{title} deleted from our database !"
  end
  puts restart
end

def start
  puts "May I help you ? (Y / N)"
    help = gets.chomp
    help = help.upcase!
      if help == "Y" || help == "YES"
        puts menu
      elsif help == "N" || help == "NO"
        puts "Ok, then have a great day ! \n"
        sleep(3)
        puts start
      else puts "Please, type a valid entrance : 'Y' or 'N' ! \n"
        puts start
      end
end

def menu
  puts "What would you like to do ? \n"
  puts "-- add : if you wanna add a movie"
  puts "-- update : if you wanna update a movie rating"
  puts "-- display : if you wanna display all the avalaible movies"
  puts "-- delete : if you wanna delete a movie \n"
  puts crud
end

def short_menu
  puts "Do you wanna do something else ?"
  puts "add | update | display | delete \n"
  puts crud
end

def crud
  puts "Make your choice !"
  case gets.chomp
    when "add" then add
    when "update" then update
    when "display" then display
    when "delete" then delete
    else puts "Type a valid entrance !"
  end
end

def restart
  sleep(3)
  puts ""
  puts short_menu
end

puts start
1 Like

Here’s my program. Similar to other posts here, I organized it into methods, which access a hash via global variable $movies. One difference is that I sort of combined the list of options with a list of the actual methods (see def menu). This might make configuration easier (but on the other hand, adding a menu option requires also creating a method for it).

For example, the name of method add can be returned with method(:add).name. This returns a string “add”. And you can call a method with method(:add).call. This was the only way I could find to call the method name from within the hash print loop.

def add
  puts "Please enter a title."
  title = gets.chomp.to_sym
  if $movies[title] != nil
    puts "#{title} is already on the list."
  else
    puts "Thanks.  Now please enter a rating for #{title}."
    rating = gets.chomp.to_i
    $movies[title] = rating
    puts "Added #{title} (#{$movies[title]})"     
  end
end # def

def update
  puts "What movie do you want to update?"
  title = gets.chomp.to_sym
  if $movies[title].nil?
    puts "#{title} is not in the list."
  else
    puts "Please enter a rating for #{title}."
    rating = gets.chomp.to_i
    $movies[title] = rating
    puts "#{title} updated (#{rating})"
  end
end # def

def display
  puts "=============================="
  $movies.each do |title,rating| 
    puts "#{title}: #{rating}"
  end
  puts "=============================="
end # def

def delete
  puts "What movie do you want to delete?"
  title = gets.chomp.to_sym
  if $movies[title].nil?
    puts "Error: #{title} doesn't exist."
  else
    $movies.delete(title)
    puts "OK. Deleted #{title}."
  end
end # def

def exit
  abort
end

def menu
  options = {
    "1" => method(:add),
    "2" => method(:update),
    "3" => method(:display),
    "4" => method(:delete),
    "5" => method(:exit)
  }
  puts "Please choose an option:"
  options.each do |k,v|
    puts "#{k}: #{v.name}"
  end
  choice = gets.chomp
  if options[choice].nil?
    puts "Error: not a valid option."
    menu
  else
    options[choice].call
    menu
  end
end # def

$movies = { 
  "Alien": 7,
  "Matrix": 7
}

menu

Hello!

I recently completed this exercise - but as I tested my program I realised that none of my titles and ratings are saving to my movies hash.

I went back and tested the original Codecademy version at the beginning of the lesson, and the titles are also not saving in that program!

Has anyone else come across this problem? Here is my code:

movies = {
  findingNemo: 5
}

puts "What would you like to do? "
choice = gets.chomp.downcase
case choice 
when 'add'
  puts "Enter a movie title: "
  title = gets.chomp
  if movies[title.to_sym].nil?
    puts "Enter a rating between 1 - 5: "
    rating = gets.chomp
    movies[title.to_sym] = rating.to_i
    puts "Title and Rating added!"
  else puts "Movie already exists"
  end
when 'update'
  puts "Enter a movie title: "
  title = gets.chomp
  if movies[title.to_sym].nil?
    puts "Movie doesn't exist"
  else 
    puts "Enter a rating between 1 -5: "
    rating = gets.chomp
    movies[title.to_sym] = rating.to_i
  end
when 'display'
  movies.each do |movie, rating| 
    puts "#{movie}: #{rating}"
  end
when 'delete'
  puts "Enter a movie title: "
  title = gets.chomp
  if movies[title.to_sym].nil?
    puts "Movie doesn't exist"
  else movies.delete(title.to_sym)
  end
else puts "Error!"
end