如何使嵌套表单的输出保持其准确的原始顺序,尽管有排列,使用索引操作和索引模板?

How to get the output of a nested form to stay in its exact original order, despite permutations, using the index action & index template?

我在 post Url 和文本中使用嵌套表单。通过 javascript,我允许对这两个字段进行任何排列,例如Url1 文本 1 文本 2 Url2 或 Url1 文本 1 Url2 文本 2 等

提交表单并重定向到 index.html.view 后,我将尝试保留我决定在表单中使用的任何排列的原始顺序,即如果我决定 post Text1 Url1 Url2 Text2 Url3 我需要在浏览器中显示完全相同的排列。

Post 表单代码

Post 型号

 class Post < ActiveRecord::Base
   has_many :texts
   has_many :urls    
   accepts_nested_attributes_for :texts, :urls 
 end

文本模型

 class Text < ActiveRecord::Base
  belongs_to :post 
 end

Url 型号

 class Url < ActiveRecord::Base
  belongs_to :post
 end

架构

 ActiveRecord::Schema.define(version: 20160215123916) do

 create_table "posts", force: :cascade do |t|
 t.datetime "created_at", null: false
 t.datetime "updated_at", null: false
  end

 create_table "texts", force: :cascade do |t|
  t.text     "textattr"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.integer  "post_id"
 end

 add_index "texts", ["post_id"], name: "index_texts_on_post_id"

 create_table "urls", force: :cascade do |t|
  t.string   "urlattr"
  t.datetime "created_at", null: false
  t.datetime "updated_at", null: false
  t.integer  "post_id"
 end

 add_index "urls", ["post_id"], name: "index_urls_on_post_id"

end

Posts 控制器

  class PostsController < ApplicationController

  def index
    @posts = Post.includes(:texts, :urls).all.order(created_at: :desc)
  end

  def new
    @post = Post.new 
   end 

  def create
   @post = Post.new(post_params) 
    if @post.save 
      redirect_to '/posts'
    else 
      render 'new'
    end 
  end

   private 
    def post_params 
        params.require(:post).permit(:texts_attributes => [:textattr], :urls_attributes => [:urlattr])
    end 
 end

Index.html.erb(尝试失败)

<% @posts.each do |post| %> 

<% post.texts.each do |text|%>
 <%= text.textattr %> <br> 
<% end %>

<% post.urls.each do |url|%>
 <%= url.urlattr %> <br> 
<% end %> 

<% end %> 

Index.html.erb(尝试失败)

   <% @posts.each do |post| %> 

    <% [post.texts, post.urls].flatten.sort_by { |c| [c.created_at] }.each do |content| %>
      <% if content.class.name == "Text" %>
        <%= content.textattr %> 
      <% elsif content.is_a? Url %>
         <%= content.urlattr %> 
      <% end %> 
    <% end %>

  <% end %>  

根据我之前的回答,您肯定需要将 textsurls 对象放入一个 table/model 中。这将允许您为它们分配 "order" 值。


我会向 texts / urls 添加一个 order 值,然后使用 child_index 值填充它:

#app/views/posts/new.html.erb
<%= form_for @post do |f| %>
  <%= f.fields_for :meta do |t| %>
    <%= t.text_field :textattr %>
    <%= t.hidden_field :order, t.index %>
  <% end %>
  <%= f.submit %>
<% end %>

根据文档:

When a collection is used you might want to know the index of each object into the array. For this purpose, the index method is available in the FormBuilder object.

<%= form_for @person do |person_form| %>
  ...
  <%= person_form.fields_for :projects do |project_fields| %>
    Project #<%= project_fields.index %>
    ...
  <% end %>
  ...
<% end %>

--

这将允许您将 order 属性传递给您的数据库:

#app/controllers/posts_controller.rb
class PostsController < ApplicationController
  def create
    @post = Post.new post_params
    @post.save
  end

  private

  def post_params
    params.require(:post).permit(meta_attributes: [:order, :textattr])
  end
end

更新

我刚试过这种方法,可以确认它有效 (index):

我唯一要说的是你的模型中可能没有 order 列,尽管它不应该返回合并错误。

我注意到您使用的是过时的 javascript 代码,您可以尝试不使用该代码看看会发生什么吗?

作为 ,您需要添加一个 order 列(或 position - 调用列 order 会导致与生成的 SQL 混淆).

我认为主要问题是您的 coffeescript code。您需要为添加的每一行生成一个隐藏输入,并为您添加的行使用一个 current_index 计数器:

current_index = 0

addText = ->
 html = """
 <br>
  <textarea 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}" />
 """

 $("#new_post input[type='submit']").before(html)
 current_index += 1

addUrl = ->
 html = """
 <br>
  <input type="url" name="post[things_attributes][#{current_index}][url]" id="post_things_attributes_#{current_index}_url">
  <input type="hidden" name="post[things_attributes][#{current_index}][order]" id="post_things_attributes_#{current_index}_order" value="#{current_index}" />
 """

 $("#new_post input[type='submit']").before(html)
 current_index += 1

在您的 index.html.erb 中,按 order 列排序 Things

<% @posts.each do |post| %>
  <% post.things.order(:order).each do |thing| %>
    <br>
    <%= thing.try(:text) %>
    <%= thing.try(:url) %>
  <% end %>

  <br>
<% end %>

还值得注意的是,cocoon gem 很好地处理了这种动态嵌套表单模式。我建议您看一下并在您的项目中使用它。