我的rails应用上的修改功能正在复制我的数据

时间:2018-02-22 13:31:37

标签: ruby-on-rails nested-forms

我正在为我的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

Recipe_Ingredient Model

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%>

非常感谢任何帮助。

2 个答案:

答案 0 :(得分:0)

此代码将表单上的所有成分添加到配方的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

答案 1 :(得分:0)

您唯一需要做的就是在重新添加之前检查配方的嵌入物中是否已包含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