Rails:需要帮助理解连接 table、嵌套形式、关联
Rails: Need help understanding a join table, nested forms, associations
我是一名学习 Rails 的学生,我的项目是制作 Recipes 应用程序。我的食谱应用程序有模型 Recipe
、Ingredient
和其他东西,但重要的是 Ingredient
必须是 table 中唯一的成分。一行只是一个 ID 和名称。 table 中只能有一个 "rice",因此任何使用大米作为原料的 Recipe
都使用同一行。这样(我猜)我可以通过 Ingredient
s 过滤 Recipe
s。
当 creating/editing 和 Recipe
时,我必须使用嵌套表格,这样用户就可以在一个屏幕上填写食谱信息和配料,包括添加新的 Ingredients
,并从下拉列表中选择成分 select。在编辑中,用户还可以从 Recipe
.
中删除(取消关联)和 Ingredient
我知道我需要一个连接table(recipes_ingredients??如果是这样,模型叫什么,RecipesIngredient
?
我不太明白这个嵌套表单是如何工作的。我要为所有 Ingredient
创建一个 fields_for
?如何解离和创造?
也许有人可以为我指明正确的方向,让我可以阅读相关内容。绞尽脑汁想了半天,还把这个项目翻了两遍。我很沮丧,但我觉得我已经接近理解它了。
我也尝试过使用 simple_form 和 cocoon,但我觉得这让我更加困惑。
关于这个主题的任何启示都会令人惊叹。谢谢你。
这是一个相当典型的连接 table 设置:
这里我们有一个名为 ingredients
的规范化 table,它用作成分的主记录,recipe_ingredients
与 recipe
table 连接.
在 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
的原因是后者是 "headless" 因为没有模型。在您意识到无法访问其他列(例如数量)之前,这似乎是个好主意。
在为 has_many through:
命名连接 table 时,由于 Rails 从 class 解析名称的方式,您应该遵循 [thing in singular]_[thing in plural]
的方案=66=] 名字。例如,使用 recipes_ingredients
会导致缺少常量错误,因为 Rails 会尝试加载 Recipes::Ingredient
。连接模型本身应命名为 SingularSingular
.
您当然也可以将 join tables 命名为任何适合域的名称。
要添加嵌套行,您可以使用 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 %>
然而,嵌套字段在很多方面都是允许同时创建/修改多个模型的障碍。将所有内容混合在一起的用户体验和应用程序流程并不理想。
为了提供良好的用户体验,应用增量保存可能是一个更好的主意(用户在使用 AJAX 在后台添加配料之前保存食谱)并通过一系列 ajax POST 请求 /recipies/:recipe_id/ingredients
。但这是整个教程本身的主题,在您了解基础知识后很可能会重新访问。
参见:
您用简单的词描述了多对多关联。
所以首先请看一下指南https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
您需要3个模型。配方模型、成分模型和 Recipe_Ingredient 模型。
我猜你已经有了配方和成分这两个模型,所以让我们看看连接 table-模型。
首先生成迁移:
rails generate migration create_recipe_ingredients
在 db/migrate/***create_recipe_ingredients.rb
创建连接 table
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.
我是一名学习 Rails 的学生,我的项目是制作 Recipes 应用程序。我的食谱应用程序有模型 Recipe
、Ingredient
和其他东西,但重要的是 Ingredient
必须是 table 中唯一的成分。一行只是一个 ID 和名称。 table 中只能有一个 "rice",因此任何使用大米作为原料的 Recipe
都使用同一行。这样(我猜)我可以通过 Ingredient
s 过滤 Recipe
s。
当 creating/editing 和 Recipe
时,我必须使用嵌套表格,这样用户就可以在一个屏幕上填写食谱信息和配料,包括添加新的 Ingredients
,并从下拉列表中选择成分 select。在编辑中,用户还可以从 Recipe
.
Ingredient
我知道我需要一个连接table(recipes_ingredients??如果是这样,模型叫什么,RecipesIngredient
?
我不太明白这个嵌套表单是如何工作的。我要为所有 Ingredient
创建一个 fields_for
?如何解离和创造?
也许有人可以为我指明正确的方向,让我可以阅读相关内容。绞尽脑汁想了半天,还把这个项目翻了两遍。我很沮丧,但我觉得我已经接近理解它了。
我也尝试过使用 simple_form 和 cocoon,但我觉得这让我更加困惑。
关于这个主题的任何启示都会令人惊叹。谢谢你。
这是一个相当典型的连接 table 设置:
这里我们有一个名为 ingredients
的规范化 table,它用作成分的主记录,recipe_ingredients
与 recipe
table 连接.
在 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
的原因是后者是 "headless" 因为没有模型。在您意识到无法访问其他列(例如数量)之前,这似乎是个好主意。
在为 has_many through:
命名连接 table 时,由于 Rails 从 class 解析名称的方式,您应该遵循 [thing in singular]_[thing in plural]
的方案=66=] 名字。例如,使用 recipes_ingredients
会导致缺少常量错误,因为 Rails 会尝试加载 Recipes::Ingredient
。连接模型本身应命名为 SingularSingular
.
您当然也可以将 join tables 命名为任何适合域的名称。
要添加嵌套行,您可以使用 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 %>
然而,嵌套字段在很多方面都是允许同时创建/修改多个模型的障碍。将所有内容混合在一起的用户体验和应用程序流程并不理想。
为了提供良好的用户体验,应用增量保存可能是一个更好的主意(用户在使用 AJAX 在后台添加配料之前保存食谱)并通过一系列 ajax POST 请求 /recipies/:recipe_id/ingredients
。但这是整个教程本身的主题,在您了解基础知识后很可能会重新访问。
参见:
您用简单的词描述了多对多关联。
所以首先请看一下指南https://guides.rubyonrails.org/association_basics.html#the-has-many-through-association
您需要3个模型。配方模型、成分模型和 Recipe_Ingredient 模型。
我猜你已经有了配方和成分这两个模型,所以让我们看看连接 table-模型。
首先生成迁移:
rails generate migration create_recipe_ingredients
在 db/migrate/***create_recipe_ingredients.rb
创建连接 table
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.