我有一个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;。
这里发生了什么?谢谢大家的帮助!
答案 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
部分是您从new
和edit
查看的。
当然,您的表单代码正在向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/