Rails只传递编辑提交时已更改的参数

时间:2016-08-28 03:51:48

标签: ruby-on-rails ruby

我有一个编辑表单,预填充当前值。它是一个自定义编辑屏幕(不是rails使用的默认编辑屏幕)以及我使用它的是用户提交将被投票并可能最终应用于记录的更改。但是,在投票的时候,其他东西可能已经改变,如果他们没有提交更改,我不想覆盖这些更改。

编辑:改为我更具体的案例,希望答案对它有用......

我有以下表格:Recipes,RecipeIngredients,RecipeSteps,RecipeChanges。在我的食谱的展示视图中,它显示所有成分/步骤,然后有一个选项卡,然后只更改成分/步骤到表单,以允许用户提交更改。我不希望应用这些更改。相反,我试图创建一个投票系统,人们可以在投票系统上投票。所以我决定将表单中的参数转换为json字符串并将其保存在单个列下的RecipeChanges表中(而不是使用两个表进行成分更改和步骤更改)。下面是表单的代码(删除了html以便更容易看到rails的内容):

<%= form_for @recipe, url: recipe_recipe_changes_path(@recipe), html: {method: "post"}, remote: true do |f| %>
    <%= f.fields_for :recipe_ingredients, f.object.recipe_ingredients.order(:order) do |ff| %>
        <%= ff.hidden_field :order, class: "position" %>
        <%= ff.text_field :ingredient, placeholder: "Add Ingredient (e.g. 3 cups cooked rice)" %>
        <label><%= ff.check_box :_destroy %>Remove</label> 
    <% end %>
    <%= f.fields_for :recipe_steps do |ff| %>
        <%= ff.hidden_field :order, class: "position"%>
        <%= ff.text_area :step %>
        <label><%= ff.check_box :_destroy %>Remove</label> 
    <% end %>
    <%= submit_tag "Submit", class: "button" %>
<% end %>

所以这会将配方对象发送到我的RecipeChange控制器,在那里我处理params将它们保存为json字符串,如下所示:

def create
    @change = RecipeChange.new
    @change.recipe_id = params[:recipe_id]
    @change.new_recipe = recipe_change_params.to_json
    #if @change.save
      #add alert for successfully adding
    #else
      # add code for error handling
    #end
  end

这就像我想要的那样,除了它保存所有的成分/步骤,我只想保存他们已经改变的东西。关于如何做到这一点,我有两个想法,但不知道如何实现它。

  1. 单击提交按钮时检查字段是否已更改,仅发送已编辑的字段(不确定是否可能)

  2. 在控制器中抓取原始配方(我有id,这样很容易)并循环通过配料/步骤并比较它们并删除任何相同的....这是我认为的方法会更好,但不知道如何循环哈希来完成这个

2 个答案:

答案 0 :(得分:0)

看看ActiveModel :: Dirty。 http://api.rubyonrails.org/classes/ActiveModel/Dirty.html#method-i-changed

您可以执行以下操作:

changes = bag.changed_attributes并获取已更改的属性的哈希值,然后保存带有bag.update_attributes(changes)的属性。

答案 1 :(得分:0)

现在有点老了,但我遇到过相同或类似的情况,想和别人分享。

在我的情况下,我根据#new动作中的现有对象填充一些嵌套的表单字段。但是,在我的#create动作中,我不想保存这些嵌套的形式参数,除非它们与原始现有对象相比实际被修改。

在这种情况下,ActiveModel::Dirty始终为true,因为它会比较[nil, "value"]

我首先尝试修改我的#create操作中的params并将它们与原始现有对象similar to this discussion进行比较,但这很麻烦并且感觉不对。

我最后保存了所有记录,然后在我的模型中使用实例方法进行清理,我在控制器的#create操作中保存后调用。仍感觉有点脏,但它正在发挥作用。

示例:

# controllers/changes_controller.rb  
# ChangeController#create
def create
  # ... shortened for example ...
  if @instance.save
    @instance.remove_clean_changes
    format.html
  end
end


# models/change.rb
# Change#remove_clean_changes
# Loop over all original objects and compare the necessary attributes 
# to the changes. If they match, they are clean and should be deleted.
def remove_clean_changes
  original_objects = self.original_objects
  changes = self.changes
  original_objects.each do |original_object|
    changes.each do |change|
      change.destroy if (change.attribute_one == original_object.attribute_one &&
                          change.original_object_id == original_object.id)
    end
  end
end