Rails:需要帮助理解连接 table、嵌套形式、关联

Rails: Need help understanding a join table, nested forms, associations

我是一名学习 Rails 的学生,我的项目是制作 Recipes 应用程序。我的食谱应用程序有模型 RecipeIngredient 和其他东西,但重要的是 Ingredient 必须是 table 中唯一的成分。一行只是一个 ID 和名称。 table 中只能有一个 "rice",因此任何使用大米作为原料的 Recipe 都使用同一行。这样(我猜)我可以通过 Ingredients 过滤 Recipes。

当 creating/editing 和 Recipe 时,我必须使用嵌套表格,这样用户就可以在一个屏幕上填写食谱信息和配料,包括添加新的 Ingredients,并从下拉列表中选择成分 select。在编辑中,用户还可以从 Recipe.

中删除(取消关联)和 Ingredient

我知道我需要一个连接table(recipes_ingredients??如果是这样,模型叫什么,RecipesIngredient

我不太明白这个嵌套表单是如何工作的。我要为所有 Ingredient 创建一个 fields_for?如何解离和创造?

也许有人可以为我指明正确的方向,让我可以阅读相关内容。绞尽脑汁想了半天,还把这个项目翻了两遍。我很沮丧,但我觉得我已经接近理解它了。

我也尝试过使用 simple_form 和 cocoon,但我觉得这让我更加困惑。

关于这个主题的任何启示都会令人惊叹。谢谢你。

这是一个相当典型的连接 table 设置:

这里我们有一个名为 ingredients 的规范化 table,它用作成分的主记录,recipe_ingredientsrecipe 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 attributesfields_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.