I got into a dilemma about using has_many, :through.
Suppose I am trying to model a restaurant’s menu through Rails. And suppose this restaurant can have several different kinds of menus, depending on the kind of the meal.
For instance, we would have a menu for the meal type breakfast, a menu for lunch, and so forth. And we would also like to add functionality for adding a kids menu and adults menu, etc.
Clearly, we should have a Menu and a Food class, we also need a join table for these to specify the different menus and the HABTM relationship between them.
But how do we deal with the Meal Type?
Note that a Meal Type belongs_to many Foods, but only belongs to one Menu. I feel that adding it to the previous join table would be inefficient.
In this example, I think I would solve by creating a new model, MealType, and writing that a Food has_many :meal_types, :through meals.
Then updating the Menu model, since a Menu can only have one meal type. This means I would have a has_one relationship with MealTypes for each menu. Briefly:
Foods class:
has_many Menus, :through menu_food_join_table
has_many MealTypes, :through meals
Menu class:
has_many Foods, :through menu_food_join_table
has_one MealType
MealType class:
belongs_to Foods, :through meals
belongs_to Menus
And here I arrived at my dilemma: this code stinks, at least to me. It doesn’t seem practical to have several tables for a simple relationship as this. And I don’t think I should add a MealType field to Foods, since some foods could be on several meals (like Coke).
Neither should I add a MealType to Menus, since I want to be able to separate foods by meal types as well (if I wanted to show only the foods that are allowed at certain meals, for instance).
What would you do in this case? I must confess I don’t have a lot experience with OO design, which is why I came here.
My final solution
Here is the solution I chose to solve the problem:
Since my real goal was to generate menus algorithmically, and since in this work I don’t have to save any of the generated menus, I destroyed the Menu model and created a Meal model.
Then I added a has-many Meals relationship to the Food model, through a join table. The only thing in the Meal database are the types of meals I want to be able to create (breakfast, lunch, dinner, etc). A meal has-many Foods through the same join table.
I still have the Menu controller and view, which I use to create a MenuFactory.
This MenuFactory is a standard factory pattern, which takes in the number of days I want to generate the menu for and the specific algorithm for the restaurant (for instance, the restaurant only serves plates with less than 300 calories) and spits out the entire menu. The rest is simple programming.
You seem to be overcomplicating things. You have one restaurant then it has one breakfast menu, one lunch menu, one dinner menu. That’s just three menus – I don’t think you need to model the type at all.
So really you just need
Menu:
has_many menu_items
MenuItem:
belongs_to menu
I suppose you could argue that a menu item could possibly be on more than one menu, like having breakfast items on the lunch menu – but if you don’t need to get that complicated then don’t.
If what you’re trying to do with the menu is more complicated than that then I would suggests your main problem is that you haven’t really defined what the problem is very well and you’ve jumped into trying to build a database to represent something you haven’t defined clearly.