【问题标题】:The edit feature on my rails app is duplicating my data我的 Rails 应用程序上的编辑功能正在复制我的数据
【发布时间】:2018-02-22 13:31:36
【问题描述】:

我正在为我的 rails 应用程序制作一本食谱书。我有嵌套在食谱下的成分。我可以创建一个食谱并添加配料。但是,当我去编辑食谱时,它会复制表格中的所有成分。然后它将显示在视图页面中重复的所有成分,当我删除一个重复的成分项目以只有一个时,它会删除这两个项目。我们也不允许在这个项目中使用accepts_nested_forms_for,因此我有自定义编写器

配方模型

class Recipe < ApplicationRecord
  belongs_to :user, required: false
  has_many :recipe_ingredients
  has_many :ingredients, through: :recipe_ingredients

  validates :name, presence: true
  validates :instructions, length: {minimum: 5}
  validates :cooktime, presence: true

  def self.alphabetical
      self.order(name: :asc)
  end

  def ingredients_attributes=(ingredients_attributes)
     ingredients_attributes.values.each do |ingredients_attribute|
      if !ingredients_attribute.empty? &&
        new_ingredient = 
         Ingredient.find_or_create_by(ingredients_attribute)
        self.ingredients << new_ingredient
      end
    end
  end
end

成分模型

class Ingredient < ApplicationRecord
  has_many :recipe_ingredients
  has_many :recipes, through: :recipe_ingredients

  def self.alphabetical
      self.order(name: :asc)
  end
end

配方_成分模型

class RecipeIngredient < ApplicationRecord
  belongs_to :recipe, required: false
  belongs_to :ingredient, required: false
end

配方控制器

class RecipesController < ApplicationController
  before_action :authenticate_user!

  def new
    @recipe = Recipe.new
    3.times do
      ingredient = @recipe.ingredients.build
    end
  end

  def index
    @recipes = current_user.recipes.alphabetical
  end

  def create
    @recipe = current_user.recipes.new(recipe_params)
        if @recipe.save
          redirect_to recipe_path(@recipe)
        else
          render :new
        end
  end

  def show
      @recipe = Recipe.find(params[:id])
      @ingredients = @recipe.ingredients.alphabetical
  end

  def edit
    @recipe = Recipe.find(params[:id])
  end

  def update
    @recipe = Recipe.find(params[:id])
      if @recipe.update(recipe_params)
        redirect_to @recipe
      else
        render :edit
      end
  end

  def destroy
    @recipe = Recipe.find(params[:id])
    @recipe.delete
    redirect_to recipes_path
  end

  private

  def recipe_params
    params.require(:recipe).permit(:name, :instructions, :cooktime, 
:ingredient_ids => [], ingredients_attributes: [:recipe_id, :name])
  end

end

食谱展示页面

<h1> Recipe for <%=@recipe.name%></h1>

<h4>Recipe Instructions: <%=@recipe.instructions%></h4>
<h4>Cook Time: <%=@recipe.cooktime%></h4>
</ul>
<h4> Ingredients: </h4>

<% @ingredients.each do |ingredient|%>
  <li><%=ingredient.name %></li>
<%end%>
</ul>
<%=link_to "Ingredients", recipe_ingredients_path(@recipe, 
@ingredients)%>
<br>
<%=link_to "Delete Recipe", recipe_path(@recipe), :method => "delete" 
%>
<br>
<%=link_to "Edit Recipe", edit_recipe_path(@recipe) %>
<br>
<%=link_to "All Recipes", recipes_path %>
<br>

这里是编辑和新表单

<%= form_for @recipe do |f| %>
  <%=f.label :name, "Name" %>
  <%=f.text_field :name %>
  <br>
  <%=f.label :instructions, "Instructions" %>
  <%=f.text_area :instructions, :rows => 3 %>
  <br>
  <%=f.label :cooktime, "Cook Time" %>
  <%=f.text_field :cooktime %>
  <br>
  <%#= f.collection_check_boxes :ingredient_ids, Ingredient.all, :id, 
 :name %>

  <%= f.fields_for :ingredients, @ingredient do |ingredient_fields| %>
  <br>
  <div class = >
     <%= ingredient_fields.label :name, "Ingredient" %>
     <%= ingredient_fields.text_field :name %>
  <% end %>

  <%=f.submit%>

非常感谢任何帮助。

【问题讨论】:

  • 我敢打赌编辑页面会做一个 POST 从而导致创建
  • 是的,可能是这样。它几乎看起来像是再次执行新/创建操作并创建了 3 个以上的成分。我如何指定不这样做?

标签: ruby-on-rails nested-forms


【解决方案1】:

此代码每次都将表单上的所有成分添加到配方的ingredients 关系中。

 def ingredients_attributes=(ingredients_attributes)
     ingredients_attributes.values.each do |ingredients_attribute|
      if !ingredients_attribute.empty? &&
        new_ingredient = 
         Ingredient.find_or_create_by(ingredients_attribute)
        self.ingredients << new_ingredient
      end
    end
  end

在你开始推入返回的属性之前,你应该清除成分关系

def ingredients_attributes=(ingredients_attributes)

     self.ingredients.destroy_all # <- this will clear down ingredients

     ingredients_attributes.values.each do |ingredients_attribute|
      if !ingredients_attribute.empty? &&
        new_ingredient = 
         Ingredient.find_or_create_by(ingredients_attribute)
        self.ingredients << new_ingredient
      end
    end
  end

【讨论】:

  • 当我编辑表单时,它仍然会创建成分的副本
【解决方案2】:

您唯一需要做的就是在(重新)添加之前检查new_ingredient 是否已经包含在配方的成分中。

你可以这样做:

#recipe.rb
def ingredients_attributes=(ingredients_attributes)
  ingredients_attributes.values.each do |ingredients_attribute|
    if !ingredients_attribute.empty? &&
      new_ingredient = 
        Ingredient.find_or_create_by(ingredients_attribute)
      self.ingredients << new_ingredient if !self.ingredients.include?(new_ingredient)
    end
  end
end

【讨论】:

    猜你喜欢
    • 2022-08-16
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-11-14
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多