Rails嵌套表单 - 编辑操作& edit.html.erb不会显示表单或相关的帖子内容

时间:2016-02-19 18:34:30

标签: javascript ruby-on-rails ruby forms ruby-on-rails-4

我创建了一个表单,用户可以通过单击文本或URL按钮动态添加嵌套表单字段。提交表单后,内容将显示在视图模板中。但是,当我在/posts/id/edit编辑(并希望然后更新)帖子时,帖子内容不会出现在编辑视图模板中 - 它是浏览器中的空白页面。

log of SQL

真的很感谢你的帮助!谢谢!

发布模型

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

1 个答案:

答案 0 :(得分:1)

您的结构存在一些问题:

  1. 您的form_for
  2. 中没有任何字段
  3. 您正在为fields_for定义手动字段( BIG no no)。
  4. <强>的form_for

    当您创建form_for时,Rails使用form objectmodel获取数据,并将其输出为HTML表单。

    此输出在渲染时完成,无论使用javascript进行多少手动提升,都不会改变:

    <%= form_for @post do |f| %>
       # you need fields in here
       <%= f.submit %>
    <% end %>
    

    调试方法是检查页面的sourceRight-Click > View Source)。如果<form>元素存在,则表示form_for方法正在运行:

    enter image description here

    另外,请记住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块。

    虽然您的代码不正确,但这是非常不切实际的。有大量资源可以指引您朝着正确的方向前进:

      
        
    1. RailsCasts Nested Forms
    2.   
    3. Cocoon宝石(强烈推荐)
    4.   
    5. NoMethodError within nested model form(我自己的帖子)
    6.   

    简而言之,您需要使用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。)

    -

    长篇大论;你收到我的电子邮件,如果你想让我特意跟你一起去。