编辑插入新记录

时间:2014-05-25 18:21:25

标签: ruby-on-rails ruby postgresql activerecord

我有一个Rails 4应用程序,其中包含以下代码:

my _form_html.erb

<%= nested_form_for @store, :html => {:multipart => true, :honeypot => true} do |f| %>
   <%= f.text_field :name %>
   <% if params[:action] == "new" %>
      <textarea name="store[products_attributes][0][product_fields_attributes][0][text_content]"></textarea>
   <% else %>
      <textarea name="store[products_attributes][0][product_fields_attributes][0][text_content]">VALUE</textarea>
   <% end %>
   <%= f.submit%>
<% end %>

我的控制器如下:

before_action :set_store, only: [:show, :edit, :update, :destroy]

def new
  @store = Store.new
end

def edit
end

def create
  @store = Store.new(store_params)
  respond_to do |format|
     if @store.save
        format.html { redirect_to @store, notice: 'Store was successfully created.'}
        format.json { render action: 'show', status: :created, location: @store }
     else
        format.html { render action: 'new' }
        format.json { render json: @store.errors, status: :unprocessable_entity }
     end
  end
end

def update
   respond_to do |format|
      if @store.update(store_params)
        format.html { redirect_to @store, notice: 'Store was successfully updated.' }
        format.json { head :no_content }
      else
        format.html { render action: 'edit' }
        format.json { render json: @store.errors, status: :unprocessable_entity }
      end
   end

def set_store
  @store = Store.find(params[:id])
end

def store_params
  params.require(:store).permit(:name, products_attributes: [:id, { product_fields_attributes: [:id, :text_content] } ])
end

我的edit.html.erb看起来像是:

<h3>Edit</h1>
<%= render 'form' %>

我的new.html.erb看起来像是:

<h3>Add New</h1>
<%= render 'form' %>

并在我的rails控制台中点击&#34;更新&#34;看起来像:

Started PATCH "/stores/sNx92thyjcP_jw" for 127.0.0.1 at 2014-05-27 17:10:46 -0600
Processing by StoresController#update as HTML
Parameters: {"utf8"=>"✓", "authenticity_token"=>"nFUg4ynXYyg99rPPPoa3uO/iHP4LT1XlOz3Vm3Zm4Z0=", "store"=>{"name"=>"Testing", "description"=>"", "products_attributes"=>{"0"=>{"type_of"=>"Book", "product_fields_attributes"=>{"0"=>{"text_content"=>"testing testing testing 1"}}}}}, "commit"=>"Update Store", "token"=>"sNx92thyjcP_jw"}
Site Load (0.7ms)  SELECT "stores".* FROM "stores" WHERE "stores"."token" = 'sNx92thyjcP_jw' LIMIT 1
(0.2ms)  BEGIN
SQL (0.5ms)  INSERT INTO "products" ("created_at", "store_id", "type_of", "updated_at") VALUES ($1, $2, $3, $4) RETURNING "id"  [["created_at", Tue, 27 May 2014 23:10:46 UTC +00:00], ["store_id", 102], ["type_of", "Book"], ["updated_at", Tue, 27 May 2014 23:10:46 UTC +00:00]]
SQL (0.7ms)  INSERT INTO "product_fields" ("created_at", "text_content", "updated_at", "product_id") VALUES ($1, $2, $3, $4) RETURNING "id"  [["created_at", Tue, 27 May 2014 23:10:46 UTC +00:00], ["text_content", "testing testing testing 1"], ["updated_at", Tue, 27 May 2014 23:10:46 UTC +00:00], ["product_id", 111]]
(15.5ms)  COMMIT
Redirected to http://localhost:3000/products/sNx92thyjcP_jw
Completed 302 Found in 30ms (ActiveRecord: 17.6ms)

我的商店模特:

class Store < ActiveRecord::Base
  before_create :generate_token

  has_many :products
  accepts_nested_attributes_for :products

  def to_param
    token
  end

  private

  def generate_token
    self.token = loop do
    random_token = SecureRandom.urlsafe_base64(10, false)
    break random_token unless Store.exists?(token: random_token)
  end
end

我的产品型号:

class Product < ActiveRecord::Base
belongs_to :store
has_many :product_fields
accepts_nested_attributes_for :product_fields
end

我的产品领域型号:

class ProductField < ActiveRecord::Base
    belongs_to :product
    mount_uploader :image_content, ImageUploader
end

但是当你去编辑商店而不是更新时,它会添加一条新记录。例如,在新页面上,您输入textarea&#34;测试1&#34;,然后保存。然后,您转到编辑页面并编辑说明&#34;测试1&#34;的文本区域。要&#34;测试2&#34;,然后点击保存。现在我有两条记录:&#34;测试1&#34;和&#34;测试2&#34;。

这里发生了什么?谢谢大家的帮助!

4 个答案:

答案 0 :(得分:8)

好的,出于某种原因你正在使用nested_form_for帮助器,但你根本没有使用嵌套字段,而是手动编写嵌套textarea的html,其中包含固定的id {{ 1}?这就是它总是创建一个新的嵌套字段的原因。保存商店时,它会检查给定的ID是否存在,如果不存在(例如id [0]从不存在),它将为它创建一个新记录。

在rails中使用嵌套字段实际上非常简单,你应该写

0

您目前没有使用任何动态添加(afaik),因此您无需使用<%= form_for @store, :html => {:multipart => true, :honeypot => true} do |f| %> <%= f.text_field :name %> <%= f.fields_for :products do |product| %> <%= product.text_area :text_content %> <% end %> <%= f.submit%> <% end %> 。从例外情况来看,我假设你总是只想要一种产品?

在您的控制器中,您必须更改nested_form_for操作,同时创建初始产品才能使其正常工作。

new

这将添加一个空/新产品,然后您可以填写。

答案 1 :(得分:0)

您正在模型中使用嵌套的attributs,因此在编辑名称时,您需要创建新的关联模型。嵌套模型的ID不应该是可编辑的。

查看此文档: http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

正在使用新ID创建新实例。

  

:update_only

     

对于一对一关联,此选项允许您   指定在关联记录时如何使用嵌套属性   已经存在。通常,可以更新现有记录   使用新的属性值集或替换为全新的   包含这些值的记录。默认情况下:update_only选项是   false和嵌套属性用于更新现有记录   只有当它们包含记录的:id值时。否则是新记录   将被实例化并用于替换现有的。但是如果   :update_only选项为true,嵌套属性用于   无论是否:id,始终更新记录的属性   存在。集合关联会忽略该选项。

答案 2 :(得分:0)

我认为my _form_html.erb实际上是_form.html.erb部分是您从newedit查看的。

当然,您的表单代码正在向create操作发送请求,否则查看您的代码就没有理由创建新记录。你应该重新检查一下。顺便说一句,我没有看到使用nested_form_for的任何理由,您也可以使用form_for字段。

无论如何,当您访问edit行为即/stores/12/edit之类的路径时,它应预先填充所有字段。检查它,在定义routes时可能会出错。或者,您可能以错误的方式发送ajax请求。存在可能性。

还有一件事,没有理由使用if-else条件,因为两种情况的结果似乎相似。

<%= nested_form_for @store, :html => {:multipart => true, :honeypot => true} do |f| %>
   <%= f.text_field :name %>
   <textarea name="store[products_attributes][0][product_fields_attributes][0][text_content]"></textarea>
   <%= f.submit%>
<% end %>

答案 3 :(得分:0)

Params没有正确格式化,它们应具有以下格式:

params = { member: { avatar_attributes: { id: '2', icon: 'sad' } } }

发送id非常重要,以便允许rails搜索关联的模型。您正在发送&#34; 0&#34;作为关键而不是价值。

按照本指南创建表单:

http://api.rubyonrails.org/classes/ActionView/Helpers/FormHelper.html

关于嵌套参数的文档:

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

另外一种选择:

http://matthewrobertson.org/blog/2012/09/20/decoupling-rails-forms-from-the-database/