我创建了一个表单,用户可以通过单击文本或URL按钮动态添加嵌套表单字段。提交表单后,内容将显示在视图模板中。但是,当我在/posts/id/edit
编辑(并希望然后更新)帖子时,帖子内容不会出现在编辑视图模板中 - 它是浏览器中的空白页面。
真的很感谢你的帮助!谢谢!
发布模型
class Post < ActiveRecord::Base
has_many :things, dependent: :destroy
accepts_nested_attributes_for :things
end
事物模型
class Thing < ActiveRecord::Base
belongs_to :post
end
模式
create_table "posts", force: :cascade do |t|
t.datetime "created_at", null: false
t.datetime "updated_at", null: false
end
create_table "things", force: :cascade do |t|
t.text "text"
t.string "url"
t.integer "post_id"
end
帖子控制器
class PostsController < ApplicationController
def edit
@post = Post.find(params[:id])
end
def update
end
new.html.erb
<button id='addtext'>text</button>
<button id='addurl'>url</button>
<%= form_for @post, url: posts_path, html: { multipart: true } do |f| %>
<%= f.fields_for :thing do |ff| %>
<% end %>
<%= f.submit %>
<% end %>
posts.coffee
current_index = 0
addText = ->
html = """
<div>
<textarea placeholder="Write something..." name="post[things_attributes][#{current_index}][text]" id="post_things_attributes_#{current_index}_text"></textarea>
<input type="hidden" name="post[things_attributes][#{current_index}] [order]" id="post_things_attributes_#{current_index}_order" value="#{current_index}" />
</div>
"""
$("#new_post input[type='submit']").before(html)
current_index += 1
$ ->
$('#addtext').on('click', addText)
current_index = 0
答案 0 :(得分:1)
您的结构存在一些问题:
form_for
fields_for
定义手动字段( BIG no no)。<强>的form_for 强>
当您创建form_for
时,Rails使用form object
从model
获取数据,并将其输出为HTML表单。
此输出在渲染时完成,无论使用javascript进行多少手动提升,都不会改变:
<%= form_for @post do |f| %>
# you need fields in here
<%= f.submit %>
<% end %>
调试方法是检查页面的source
(Right-Click > View Source
)。如果<form>
元素存在,则表示form_for
方法正在运行:
另外,请记住form_for
是一种帮助方法。它需要参数并输出HTML供您使用。这不是魔术。如果它“没有显示”,则必须有合理的理由。
<强> fields_for 强>
第二步是,如果没有任何对象填充它,您的fields_for
将不会显示。
当您手动添加新的fields_for
字段时,您遇到了一个很大的问题,基本上是antipattern。
您需要执行以下操作:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def edit
@post = Post.includes(:things).find(params[:id])
@post.things.build unless @post.things.any?
end
end
#app/views/posts/edit.html.erb
<%= form_for @post, url: posts_path, html: { multipart: true } do |f| %>
<%= f.fields_for :things do |ff| %> #-> association name (plural)
<%= ff.text_area :text, placeholder: "Write Something" %>
<% end %>
<%= f.submit %>
<% end %>
fields_for
填充您传递给form_for
的父级的关联对象。因此,如果您尚未构建任何关联对象,则需要确保至少构建一个关联对象,以便相应地填充字段。
<强>嵌套强>
最后,您需要了解如何动态地将fields
附加到fields_for
块。
虽然您的代码不正确,但这是非常不切实际的。有大量资源可以指引您朝着正确的方向前进:
- RailsCasts Nested Forms
Cocoon
宝石(强烈推荐)- NoMethodError within nested model form(我自己的帖子)
醇>
简而言之,您需要使用Ruby / Rails构建所需的fields_for
方法,并使用ajax将它们附加到表单中:
#app/controllers/posts_controller.rb
class PostsController < ApplicationController
def edit
@post = Post.includes(:things).find params[:id]
@post.things.build unless @post.things.any?
respond_to do |format|
format.js
format.html
end
end
end
#app/views/posts/edit.html.erb
<%= form_for @post, authenticity_token: !request.xhr? do |f| %>
<%= render partial: "things_fields", locals: { f: f } %>
<% if !request.xhr? %>
<%= button_to "Add Thing", edit_posts_path(@post), method: :get, remote: true %>
<%= f.submit %>
<% end %>
<% end %>
#app/views/posts/_things_fields.html.erb
<%= f.fields_for :things, child_index: Time.now.to_i do |ff| %>
<%= ff.text_area :text, placeholder: "Write Something" %>
<% end %>
这样,您就可以通过fields
电话追加JS
:
#app/views/posts/edit.js.erb
$("<%=j render "edit" %>").data().appendTo("form#post);
使用此方法的技巧是使用child_index: Time.now.to_i
(为每个新添加的字段提供唯一的id
。)
-
长篇大论;你收到我的电子邮件,如果你想让我特意跟你一起去。