我是一名学习Rails的学生,我的项目是制作Recipes应用程序。我的食谱应用程序具有模型Recipe
,Ingredient
和其他功能,但重要的是,Ingredient
必须是表中该类型的唯一成分。行将只是一个ID和名称。表中只能有一个“大米”,因此任何以大米为原料的Recipe
都应使用同一行。这样(我想)可以按Recipe
个过滤Ingredient
个。
在创建/编辑Recipe
时,我必须使用嵌套表单,因此用户可以在一个屏幕上填写食谱信息和配料,包括添加新的Ingredients
以及从中选择配料选择的下拉列表。在编辑中,用户还可以从Ingredient
中删除(取消关联)和Recipe
。
我知道我需要一个联接表(recipes_ingredients ??,如果需要的话,RecipesIngredient
这个模型叫什么?
我不太了解此嵌套表单如何工作。我要为所有fields_for
创建一个Ingredient
吗?如何分离和创建?
也许有人可以向我指出正确的方向,以便我可以阅读有关此内容的信息。我已经花了很长时间思考,甚至开始了两次该项目。我感到沮丧,但我感觉我已经非常了解它。
我也尝试过使用simple_form和cocoon,但我觉得这让我更加困惑。
任何关于这个问题的见解都将是惊人的。谢谢。
答案 0 :(得分:1)
这是一个非常典型的联接表设置:
在这里,我们有一个名为ingredients
的规范化表,该表用作成分的主记录,还有一个recipe_ingredients
,与recipe
表联接。
在Rails中,我们将其设置为has_many through:
关联:
class Recipe < ApplicationRecord
has_many :recipe_ingredients
has_many :ingredients, through: :recipe_ingredients
end
class Ingredient < ApplicationRecord
has_many :recipe_ingredients
has_many :recipes, through: :recipe_ingredients
end
class RecipeIngredient < ApplicationRecord
belongs_to :recipe
belongs_to :ingredient
end
您要使用has_many through:
而不是has_and_belongs_to_many
的原因是,由于没有模型,后者是“无头的”。直到您意识到无法访问其他列(例如数量),这似乎是一个好主意。
为has_many through:
命名联接表时,由于Rails从表名解析类名的方式,您应该遵循[thing in singular]_[thing in plural]
的方案。例如,使用recipes_ingredients
会导致丢失常量错误,因为Rails会尝试加载Recipes::Ingredient
。连接模型本身应命名为SingularSingular
。
您当然也可以为适合域的名称命名联接表。
要添加嵌套行,请使用nested attributes和fields_for :recipe_ingredients
:
<%= form_for(@recipe) do |f| %>
<div class="field">
<%= f.label :name %>
<%= f.text_field :name %>
</div>
<fieldset>
<legend>Ingredients</legend>
<%= fields_for :recipe_ingredients do |ri| %>
<div class="nested_fields">
<div class="field">
<%= ri.label :ingredient %>
<%= ri.collection_select(:ingredient_id, Ingredient.all, :id, :name) %>
</div>
<div class="field">
<%= ri.number_field :quantity %>
</div>
</div>
<% end %>
</fieldset>
<% end %>
但是,嵌套字段在许多方面都是笨拙的,允许一次创建/修改多个模型。将所有内容融合在一起的UX和应用程序流程并不理想。
要提供良好的用户体验,最好采用增量保存(用户在使用AJAX在后台添加配料之前保存配方),然后通过向/recipies/:recipe_id/ingredients
进行一系列ajax POST请求来添加配料。但这是整个教程的主题,在您了解了基础知识之后,很可能会重新讨论它。
请参阅:
答案 1 :(得分:1)
您可以用简单的单词描述多对多关联。
首先,请看指南https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
您需要3个型号。配方模型,成分模型和配方成分模型。
我猜您已经有两个模型,即Recipe和Ingredient,所以让我们看一下联接表模型。
首先生成一个迁移:
rails generate migration create_recipe_ingredients
在db/migrate/***create_recipe_ingredients.rb
处创建连接表
def change
create_table :recipe_ingredients do |t|
t.integer :ingredient_id, :recipe_id
end
end
所以您的模型:
class Recipe < ApplicationRecord
has_many:recipe_ingredients
has_many:ingredients, through: :recipe_ingredients
end
class RecipeIngredient < ApplicationRecord
belongs_to :recipe
belongs_to :ingredient
end
class Ingredient < ApplicationRecord
has_many:recipe_ingredients
has_many:recipes, through: :recipe_ingredients
end
在控制台上运行并测试关联:
irb:> recipe=Recipe.first
irb:> ingre=Ingredient.first
irb:> ingre.recipes << recipe
irb:> ingre.recipes #Recipes with this ingredient
irb:> recipe.ingredients #The ingredients of this specific recipe.
irb:> Ingredient.all #List all your ingredients.
irb:> Recipe.all #List all your recipes.