我有一个Rails 4应用程序,其中我有以下代码:
我_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控制台,当我点击"更新"看起来像:
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)
My store model:
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
但是当你去编辑存储时,它不是更新,而是添加一个新记录。例如,在新页面上,您放入文本区域"Testing 1",然后保存。然后你进入编辑页面,将"Testing 1"的文本区域编辑为"Testing 2",然后点击保存。现在我有两个记录:"测试1"one_answers"测试2"。
这是怎么回事?谢谢大家的帮助!
Ok,出于某种原因,您正在使用nested_form_for
助手,但您根本不使用嵌套字段,而是手动为嵌套的textarea
编写html,具有固定id [0]
?这就是为什么它总是创建一个新的嵌套字段。当保存存储时,它将检查给定的id是否存在,如果不存在(例如id 0
从不存在),它将为它创建一个新记录。
在rails中使用嵌套字段实际上很简单,你只需要写
<%= 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
动作以创建初始产品以使此工作。
def new
@store = Store.new
@store.products.build
end
这将添加一个空的/新产品,然后您可以填充。
您正在模型中使用嵌套属性,因此在编辑名称时您正在创建一个新的关联模型。嵌套模型的ID不能被编辑。
查看这个文档:http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html
正在创建一个具有新ID的新实例。
: update_only
对于一对一的关联,此选项允许您指定在关联记录时如何使用嵌套属性已经存在。一般来说,现有的记录可以被更新使用新的属性值集,或者用一个全新的包含这些值的记录。默认情况下:update_only选项为False,并使用嵌套属性更新现有记录仅当它们包含记录的:id值时。否则就是新纪录了将被实例化并用于替换现有的。然而,如果update_only选项为true,则使用嵌套属性始终更新记录的属性,无论是否:id是礼物。对于集合关联,该选项被忽略。
我假设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 %>
参数的格式不正确,它们应该是这样的格式:
params = { member: { avatar_attributes: { id: '2', icon: 'sad' } } }
为了允许rails搜索相关的模型,发送id很重要。
您正在发送"0"作为键而不是值。按照以下指南创建表单:
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/