【问题标题】:How to create a child model from a parent如何从父模型创建子模型
【发布时间】:2015-09-25 07:45:01
【问题描述】:

这几天我一直在用 Rails 旋转五月轮。我正在使用三个模型:IngredientBaseIngredientIngredientListIngredientBase 包含一个字符串,可能是“Chicken”、“Eggs”或“Bacon”。成分将有一个 Ingredient 和一个数量。 IngredientList 会有很多成分。

我希望用户在提交 IngredientList 之前能够在成分列表/新中创建多个成分。如果不让用户提交多个表单,我怎么能做到这一点?

【问题讨论】:

  • 你的关键字是accepts_nested_attributes_for :ingredients,所以你可以用谷歌搜索找到很多东西

标签: ruby-on-rails model controller nested


【解决方案1】:

联想

您正在查看的是nested models

嵌套模型基本上允许您将属性附加到一个模型的实例;这些属性被发送到关联模型。

这是通过accepts_nested_attributes_for实现的:

#app/models/ingredient_list.rb
class IngrendientList < ActiveRecord::Base
   has_many :ingredients
   accepts_nested_attributes_for :ingredients
end

#app/models/ingredient.rb
class Ingredient < ActiveRecord::Base
   belongs_to :ingredient_list
end

因为你的模型让我很困惑,所以我为你重写了结构。我认为您对连接模型等感到困惑:

#app/models/ingredient.rb
class Ingredient < ActiveRecord::Base
   #columns id | name | weight | etc | created_at | updated_at
   has_many :recipe_ingredients
   has_many :recipes, through: :recipe_ingredients
end

#app/models/recipe_ingredient.rb
class RecipeIngredient < ActiveRecord::Base
    #columns id | recipe_id | ingredient_id | quantity | created_at | updated_at
    belongs_to :recipe
    belongs_to :ingredient
    accepts_nested_attributes_for :ingredient
end

#app/models/recipe.rb
class Recipe < ActiveRecord::Base
   #columns id | name | etc | etc | created_at | updated_at
   has_many :recipe_ingredients #-> allows extra attributes
   has_many :ingredients, through: :recipe_ingredients 
   accepts_nested_attributes_for :recipe_ingredients
end

这将使您能够创建Recipe、添加新的Ingredients,并且通常使您的模型更加健壮。

以下是如何使它与控制器和视图等一起工作:

#app/controllers/recipes_controller.rb
class RecipesController < ApplicationController
   def new
      @recipe = Recipe.new
   end
   def create
      @recipe = Recipe.new recipe_params
      @recipe.save
   end

   private

   def recipe_params
      params.require(:recipe).permit(:recipe, :params, recipe_ingredients_attributes: [:quantity, ingredient_attributes:[:name]])
   end
end

这将创建一个基本表单,但我们需要包含相关字段。有几种方法可以做到这一点,包括来自RailsCasts 的“手动”方法和使用Cocoon

需要注意的重要一点是:

每次调用嵌套表单字段时,您基本上都会得到 Rails 将f.fields_for 的另一个实例添加到您的表单中。这 这里要注意的重要一点是,您需要有 child_index fields_for 块。这是 Rails 用来识别字段的方法, 并且需要保持唯一性。

您可以在 an answer I wrote some time back 上查看更多信息。

对于您的表单,您需要以下内容:

#app/views/recipes/new.html.erb
<%= form_for @recipe do |f| %>
   <%= f.text_field :title %> 
   <%= render "ingredients", locals: {f: f, child_index: Time.now.to_i}  %>
   <%= link_to "Add Ingredient", recipes_add_field_path, class: "ingredient" %>
   <%= f.submit %>
<% end %>

#app/views/recipes/_ingredients.html.erb
<%= f.fields_for :recipe_ingredients, child_index: child_index do |ri| %>
    <%= ri.text_field :quantity %>
    <%= ri.fields_for :ingredient do |ingredient| %>
       <%= ingredient.text_field :name %>
       <%= ingredient.text_field :weight %>
    <% end %>
<% end %>

#config/routes.rb
resources :recipes do
   member "add_field", to: "recipes#add_field"
end

#app/controllers/recipes_controller.rb
class RecipesController < ApplicationController
   def add_field
      @recipe = Recipe.new
      @recipe.recipe_ingredients.build.build_ingredient
      render "new"
   end
end

#app/assets/javascripts/application.js
$(document).on("click", "a.ingredient", function(){
   $.ajax({
      url: '/recipes/add_field',
      success: function(data){
        el_to_add = $(data).html();
        $('#recipes').append(el_to_add);
      }
      error: function(data){
         alert("Sorry, There Was An Error!");
      }
   });
});

【讨论】:

  • 谢谢,我正在尝试这个答案,但在 routes.rb 中出现错误为什么我在行成员“add_field”上运行 rake db:migrate 到:“recipes#add_field” .我得到的错误是:rake aborted! ArgumentError: wrong number of arguments (2 for 0) /home/reimus/mplan/config/routes.rb:5:in block (2 levels) in ' /home/reimus/mplan/config/routes.rb:4:in block in &lt;top (required)&gt;' /home/reimus/mplan/config/routes.rb:1:in ' /home /reimus/mplan/config/environment.rb:5:in &lt;top (required)&gt;' Tasks: TOP =&gt; routes =&gt; environment
【解决方案2】:

处理嵌套关系的最佳方法是使用accept_nested_attributes

为了更好地理解这里是link

在表单中管理 ui 级别的表单是 gem

【讨论】:

猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-17
  • 2021-12-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多