Welcome to your good old neighborhood VHS store. You will build an app that tracks the store inventory, the rentals and the clients. Prepare for the 80s nostalgia.
You will be working on a six-model domain: Client
, Rental
, Vhs
, Movie
, MovieGenre
, Genre
. The associations are as follows:
- Genre has many movie_genres and movies through movie_genres,
- MovieGenre belongs to a movie and a genre,
- Movie has many movie_genres and genres through movie_genres,
- Movie has many vhs and rentals through vhs,
- Vhs belongs to a movie,
- Vhs has many rentals and clients through rentals,
- Rental belongs to a client and vhs,
- Client has many rentals and vhs through rentals.
NOTE that the below ERD does not include foreign keys -- these you need to add on your own, together with the association macros.
Client
|
^
Rental
V
|
|
Vhs >---- Movie ----< MovieGenre >---- Genre
- Carefully read the readme.
- Fork and clone this lab.
- Run
bundle
. - Check the code you have been given: see
app/models
and files in it (is there a class for every model? are all the associations set up?), seedb/schema
, seerb/seeds.rb
. Runrake db:migrate:status
to see if there are any pending migrations -- if there are, check these files and see if you need to add anything before migrating it.
NOTE ABOUT THE SEEDS: the seed
s have been commented out -- uncomment it once you've built out your migrations and associations.Also, as you can see in the file, seed
s rely on a significant amount of randomness so if you work with another person and do not share the same database, you WILL get different results in terms of number of associated instances or number of instances in general.
- Now that you know what is missing, DO NOT CODE JUST YET. Discuss with your partner the plan for the setup: what are you going to do step by step and how are you going to test if it worked.
- You must have noticed that one of the models is called
Vhs
. Inrake console
run:
'vhs'.pluralize
'vhs'.singularize
As you see, ActiveRecord perceives this word as already pluralized and it will pose problems when you're trying to apply .vhs
method on e.g. a Movie
instance (AR will look for a singularized model of Vh
). To prevent this, let's tell AR that this word is the same singular as plural -- paste this in config/environment.rb
:
ActiveSupport::Inflector.inflections do |inflect|
inflect.irregular 'vhs', 'vhs'
end
- Run
rake -T
and see what process reminder tasks are available to you (they are marked with "๐"). - Start coding the setup. Test your code frequently.
- After all your models are hooked up correctly, choose minimum five deliverables from the list below. You need to have at least one deliverable for each of the CRUD actions. The only compulsory deliverable is
Client.paid_most
(it's a READ action). The deliverables marked with "โญ๏ธ" require a bit more of pseudocoding andbinding.pry
. - After you've chosen the deliverables, tackle one by one. Majority of them require helper methods (yes, plural), the use of
binding.pry
, and a good amount of pseudocoding. When writing helper methods, please remember that:
- each method should do JUST ONE JOB,
- each method name should be descriptive,
- it's always best think about where the method should live; for instance: is it a behavior of a Client? or is it a behavior of a Vhs instance and should be called from within an instance method of a Client?
NOTE: all deliverables will make you a strong dev and will allow you for a good practice on ActiveRecord. Please spend some time on this lab, together with your partner or on your own. This lab can also be developed into a CLI that can serve as a strong portfolio piece or blog post material. Check out Danny Sasse's blog post on how his pairing partner and he implemented DRY solution.
SECOND NOTE: Please know that there is the basic solution authored by me and a solution that involves moduls authored by Danny Sasse and Simon Jacobs. Feel free to check them once you're done or if you're stuck -- they are there for you to learn from!
Build the following functionality:
READ
Rental#due_date
- returns a date one week from when the record was createdRental.past_due_date
- returns a list of all the rentals past due date, currently rented or rented in the past
CREATE
Client.first_rental
- accepts and instance of arguments needed to create a newClient
instance and a currently availableVhs
instance (or, more difficult: aMovie
instance or just aMovie
title and on that basis chooses a currently available vhs); it creates a newClient
instance and a newRental
instance withcurrent
set to true.
READ
Client.most_active
- returns a list of top 5 most active clients (i.e. those who had the most non-current / returned rentals)Client#favorite_genre
โญ๏ธ -puts
the name of the genre that the client rented the most; in counting how many times a person watched a genre, you can treat two rentals of the same movie as two separate instances;Client.non_grata
- returns a list of all the clients who have a vhs past the due date (or, more difficult: who ever missed the return date)Client.paid_most
- returns an instance who has spent most money at the store; one rental is $5,35 upfront (bonus: additional $12 charge for every late return โ do not count those that have not yet been returned)Client.total_watch_time
- returns an Integer of all movies watched by the all clients combined (assume that a rented movie is a watched movie)
UPDATE
Client#return_one
- accepts an argument of an vhs instance, finds the corresponding rental and updates the rental'scurrent
attribute fromtrue
tofalse
Client#return_all
- updatescurrent
attribute fromtrue
tofalse
on all client's rentals
UPDATE AND DELETE
Client#last_return
- updates all Client' rentals current tofalse
and deletes the Client from the database
CREATE
Vhs.hot_from_the_press
- accepts arguments used to create a new instance of aMovie
and a name of a genre; creates the movie, associates it with appropriate genre (if it exists, if it doesn't - creates one) and creates three instances of aVhs
associated with that Movie
READ
Vhs.most_used
- prints a list of 3 vhs that have been most rented in the format: "serial number: 1111111 | title: 'movie title'Vhs.all_genres
- returns a list of all genres available at the storeVhs.available_now
- returns a list of all vhs currently available at the store
READ
Movie.available_now
- returns a list of all movies currently available at the storeMovie.most_clients
โญ๏ธ - returns an instance ofMovie
that has been rented by the most peopleMovie.most_rentals
- returns a list of TOP3 All Time favorites based on number of rentalsMovie.most_popular_female_director
- returns a string that's a name of a director of the movie made by a female director with mostRental
sMovie.newest_first
- returns a list of all the movies from the most recent ones to the oldies but goldies based on the release yearMovie.longest
- returns a list of the movies from the longest to the shortestMovie#recommendation
- prints a recommendation that includes a random emoji next to the title, and in new lines: the movie description, its length, director and year of releaseMovie.surprise_me
- prints a recommendation for a random movie
DELETE
Movie#report_stolen
- deletes a random vhs instance associated with this movie that's currently not rented out and prints information: "THANK YOU FOR YOUR REPORT. WE WILL LAUNCH AN INVESTIGATION."
READ
Genre.most_popular
- returns a list of 5 most popular genres based on number of moviesGenre.longest_movies
- returns a genre whose movies length average is the highest (remember to also test it with an instance of a Genre that does not have any movies associated)
Did you find a bug? A typo? Do you have an idea for a new hot deliverable? Are you proud of a solution you've submitted and would like it to be featured as a branch here? Please create an issue describing what change you'd like to see and whether you'd like to code it. Wait for my response and if it's a ๐, go ahead: fork the repo, write code and open a PR with a description of changes.
โจ Shoutout to Danny Sasse for finding a squishing a bug in seeds!
โจ Shoutout to Danny Sasse and Simon Jacobs for providing an alternative solution that involves modules and code that follows DRY principle.