In this lab, you'll practice all of the parts of ActiveRecord - Migrations, Validations, Seeds, and Querying.
We'll be building out a restaurant domain in two stages. Remember to draw out the relationships between your models before you start building.
We'll be creating the following models:
- Restaurant
- Dish
- Tag
Migrations
- Restaurant
- name
- has many dishes
- Dish
- name
- has many tags
- Tag
- name
- has many dishes
Do you need any join tables? What data should they have?
Validations
- Restaurants need a name
- Dishes need a name and a restaurant
- Tags need a name 3 characters or longer
- Tag names can only be one word or two words, not more
- Dishes can only have one of any particular tag
Seeds
Create a seeds file that creates:
- 20 restaurants.
- Each restaurant should have 10 dishes
- Each Dish should have 3 tags
- There should be only 10 or 15 tags, with names like 'Spicy' and 'Vegetarian'
Reminder: Be DRY - use an array of names and iterate through them to create your restaurants
Querying
Write the following methods. You should use ActiveRecord query methods to get the results (i.e. you shouldn't just use .all
and use array methods!)
Note: some helper methods you will need (e.g. the relationships between the models) are not listed here. Write them anyway!
Restaurant
Restaurant.mcdonalds
- find the restaurant with the name'McDonalds'
.Restaurant.tenth
- find the tenth restaurantRestaurant.with_long_names
- find all the restaurants with names longer than 12 charactersRestaurant.max_dishes
- find the restaurant with the most dishesRestaurant.focused
- find all the restaurants with fewer than 5 dishesRestaurant.large_menu
- find all the restaurants with more than 20 dishesRestaurant.vegetarian
- all restaurants where all of the dishes are tagged vegetarianRestaurant.name_like(name)
- all restaurants where the name is like the name passed inRestaurant.name_not_like(name)
- all restaurants where the name is not like the name passed in
Dish
Dish.names
- all the names of dishesDish.max_tags
- single dish with the most tagsDish.untagged
- dishes with no tagsDish.average_tag_count
- average tag count for dishesDish#tag_count
- number of tags for a dishDish#tag_names
- names of the tags on a dishDish#most_popular_tag
- most widely used tag for a dish
Tag
Tag.most_common
- tag with the most associated dishesTag.least_common
- tag with the fewest associated dishesTag.unused
- all tags that haven't been usedTag.uncommon
- all tags that have been used fewer than 5 timesTag.popular
- top 5 tags by useTag#restaurants
- restaurants that have this tag on at least one dishTag#top_restaurant
- restaurant that uses this tag the mostTag#dish_count
- how many dishes use this tag
ActiveRecord methods you might find useful:
find
where
pluck
joins
includes
group
having
Examples and explanations here
Note: In order to test these methods, you'll probably need to have particular seed data. Create it.
Mo models, mo problems.
Add the following models to the domain:
- Customer
- Order
- Review
Migrations
- Customer
- name
- lat
- lon
- has many orders
- has many reviews
- Order
- belongs to a customer
- belongs to a restaurant
- has many dishes
- Review
- content
- rating
- date
- belongs to a customer
- belongs to a restaurant
And add to your old models
- Dish
- price
- cost (price the restaurant paid to make it)
- Restaurant
- lat
- lon
Again - what other tables do you need? Draw your relationships to find out.
Validations
- Customer name is required
- Customer lat and lon must be valid latitude and longitude (-90 < lat < 90, -180 < lon < 180)
- Order needs a customer and a restaurant
- Order needs at least one dish
- Order dishes must all be from the same restaurant
- Review must have a customer and a restaurant
- Review must have content > 10 characters
- Review rating must exist, be one of the values [1,2,3,4,5]. See Enums.
- Review customer must have made an order from the restaurant
Queries You'll need to update your old seed data and add more to be able to test these query methods.
Customer
Customer#recent_reviews
- all reviews by this customer, ordered by recencyCustomer#nearest_restaurant
- nearest restaurant to the customer's locationCustomer#top_restaurant
- restaurant where the customer has the most ordersCustomer#top_dish
- most commonly ordered dish for the customerCustomer#total_spending
- total price of all dishes orderedCustomer.top_spenders
- top 5 customers by total order price
Order
Order#total_price
- sum of the price of all the dishes.Order#profit
- difference between price and cost of all the order's dishesOrder#profitable?
- true if order profit is positiveOrder#tags
- tags of all the dishes in an orderOrder.cheapest
- lowest 5 orders by total priceOrder.most_expensive
- highest 5 orders by total price
Review
Review.median_rating
- median rating for all reviewsReview.most_recent
- most recent 10 reviews
Restaurant
Restaurant#average_rating
- average rating of a restaurantRestaurant.average_rating
- average rating across all restaurantsRestaurant.highest_rated
- highest average rated restaurantRestaurant.top_five
- top five highest rated restaurantsRestaurant#dollar_rating
- how many dollar signs is this restaurant?- $: avg_dish_price < 10
- $$: 10 < avg_dish_price < 20
- $$$: 20 < avg_dish_price < 30
- $$$$: 30 < avg_dish_price
Restaurant.most_expensive
- most expensive restaurant by average dish priceRestaurant.cheap_eats
- all $ and $$ restaurantsRestaurant.nearest_customers
- nearest 5 customersRestaurant.recent_reviews
- 5 most recent reviews of this restaurantRestaurant#best_seller
- most ordered dish for the restaurantRestaurant#most_profitable_dish
- most profitable dish(price - cost) * num orders
Dish
Dish#top_customer
- customer who has ordered a dish the most timesDish.most_ordered
- most ordered dish
Tag
Tag#nearest_restaurant(customer)
- nearest restaurant to the customer with that tag.Tag#top_rated
- top 3 rated restaurants with dishes with a tag
Read this about schema constraints. Add the appropriate schema constraints to your tables. For instance, things that have a validation for presence: true
should probably also have null: false
in the schema.
Read the section of the rails guide about N+1 queries and Eager Loading Associations. Using the ActiveRecord Logger, find out which of the methods you've written so far have an N+1 query. Fix them.