Rails has_many, :through 与不同类型关系的困境
我陷入了关于使用 has_many, :through 的困境。
假设我尝试通过 Rails 为一家餐厅的菜单建模。假设这家餐厅可以有几种不同类型的菜单,具体取决于餐食的种类。
例如,我们会有一个早餐菜单、午餐菜单等等。我们还想添加添加儿童菜单和成人菜单等的功能。
显然,我们应该有一个 Menu 和 Food 类,我们还需要一个连接表来指定不同的菜单以及它们之间的 HABTM 关系。
但我们如何处理膳食类型?
请注意,一种膳食类型属于多种食物,但仅属于一个菜单。我觉得将它添加到之前的连接表中效率会很低。
在这个例子中,我想我可以通过创建一个新模型 MealType 并编写 Food has_many :meal_types, :through Meal 来解决。
然后更新菜单模型,因为菜单只能有一种餐食类型。这意味着我将与每个菜单的 MealTypes 建立 has_one 关系。简而言之:
Foods 类:
has_many Menus, :through menu_food_join_table
has_many MealTypes, :through meals
Menu 类:
has_many Foods, :through menu_food_join_table
has_one MealType
MealType 类:
belongs_to Foods, :through meals
belongs_to Menus
在这里我陷入了困境:这段代码很臭,至少对我来说是这样。对于这样的简单关系使用多个表似乎并不实际。我认为我不应该向 Foods 添加 MealType 字段,因为有些食物可能会出现在几餐中(例如可乐)。
我也不应该在菜单中添加 MealType,因为我也希望能够按膳食类型分隔食物(例如,如果我只想显示某些膳食允许的食物)。
在这种情况下你会怎么做?我必须承认我在面向对象设计方面没有太多经验,这就是我来到这里的原因。
我的最终解决方案
这是我选择解决问题的解决方案:
由于我的真正目标是通过算法生成菜单,并且在这项工作中我不必保存任何生成的菜单,所以我销毁了 Menu 模型并创建了 Meal 模型。
然后,我通过连接表向食物模型添加了多餐关系。膳食数据库中唯一的内容是我希望能够创建的膳食类型(早餐、午餐、晚餐等)。一顿饭有很多食物通过同一个连接表。
我仍然有菜单控制器和视图,我用它来创建 MenuFactory。
这个MenuFactory是一个标准的工厂模式,它接收我想要生成菜单的天数和餐厅的具体算法(例如餐厅只提供低于300卡路里的盘子)并吐出整个菜单。剩下的就是简单的编程了。
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.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
你似乎把事情过于复杂化了。您有一家餐厅,那么它有一份早餐菜单、一份午餐菜单、一份晚餐菜单。这只是三个菜单 - 我认为您根本不需要对类型进行建模。
所以你真的只需要
菜单:
has_many menu_items
菜单项:
属于菜单
我想您可能会争辩说,一个菜单项可能位于多个菜单上,例如午餐菜单上有早餐项目 - 但如果您不需要变得那么复杂,那就不要' t。
如果您尝试对菜单执行的操作比这更复杂,那么我建议您的主要问题是您还没有真正很好地定义问题是什么,并且您已经开始尝试构建一个数据库来表示你还没有明确定义的东西。
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.