编辑插入新记录



我有一个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部分,您从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 %>

参数的格式不正确,它们应该是这样的格式:

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/

最新更新