Rails 4.2 嵌套表单--SQL 加载'Edit' 页面时自动删除嵌套表单内容

Rails 4.2 Nested Forms--SQL Automatically Deleted Nested Forms Content When Loading 'Edit' Page

我使用这个 Blog 作为在 Ruby on Rails 4.2 上学习 nested form 的指南。我尝试使用此指令中的相同步骤在 Post 模型中创建位置嵌套表单。

使用嵌套位置表单创建新的 post 后,位置内容在 post's 显示页面上正确显示。但是,当我打开 edit 页面时,位置内容全部消失了。仔细查看日志,发现如下信息:

Started GET "/categories/category#name/posts/323/edit"...
Location Load (0.1ms)  SELECT  "locations".* FROM "locations" WHERE "locations"."post_id" = ? LIMIT 1  [["post_id", 323]]
   (0.1ms)  begin transaction
  SQL (0.4ms)  DELETE FROM "locations" WHERE "locations"."id" = ?  [["id", 27]]

似乎嵌套形式创建的内容在加载编辑页面时被SQL自动删除了。

这是我的代码:

   class Post < ActiveRecord::Base
      belongs_to :user
      belongs_to :category

      has_one :location, dependent: :destroy

      accepts_nested_attributes_for :location, reject_if: lambda { |a| a['street'].blank? },
                                     allow_destroy: true
      def to_s
        title
      end
   end

位置模型:

class Location < ActiveRecord::Base
  belongs_to :post
  has_one :user, through: :post


  validates :city, presence: true
  validates :zipcode, presence: true,
             format: { with: /\A\d{5}\z/i }


end

帖子控制器:

 class Categories::PostsController < ApplicationController
    ...
    def new
        @category = Category.friendly.find(params[:category_id])
        @post = Post.new
        @post.build_location
      end

      def create
        @category = Category.friendly.find(params[:category_id])
        @post = current_user.posts.build(post_params)
        @post.category = @category

        if @post.save
          flash[:success] = "You have succesfully created a new post."
          redirect_to [@category, @post]
        else
          flash[:error] = "Error occured. Please try again."
          render :new
        end
      end

      def edit
        @category = Category.friendly.find(params[:category_id])
        @post = Post.find(params[:id])
        @post.build_location
      end

      def update
        @category = Category.friendly.find(params[:category_id])
        @post = Post.find(params[:id])
          if @post.update_attributes(post_params)
            flash[:success] = "Post was upated."
            redirect_to [@category, @post]
          else
            flash[:error] = "There was an error saving a post, please try again."
            render :new
          end
      end
    ...
    private 

        def post_params
          params.require(:post).permit(:title, :body, location_attributes: [:id, :street, :city, :zipcode, :_destroy])
        end

app/views/posts/_form.html.erb

<%= form_for [@category, @post] do |f| %>
  ...
  <strong>Location:</strong>
  <div class="well">
    <%= f.fields_for :location do |location| %>
      <%= location.label :street %>
  <%= location.text_field :street, placeholder: "If you don't want to provide your address, just put 'NA' in this field" %>

  <%= location.label :city %>
  <%= location.text_field :city %>

  <%= location.label :zipcode%>
  <%= location.text_field :zipcode %>

  <%= location.check_box :_destroy %>
  <%= location.label :_destroy, 'remove' %>
    <% end %>
  </div>

虽然按照我遵循的说明一切正常,但当我在服务器上测试我的应用程序时,我的应用程序不断出现 "silent" 错误。如何使嵌套表单中的现有数据出现在编辑页面上?

欢迎任何见解,并提前致谢!

@post.build_location 在内存中创建一个新的位置对象,因此它被传递给 update 并因此删除与 post 关联的位置。它不获取当前位置。

@post.create_location 还创建了一个新的位置对象,但将其与数据库相同。这不是你想要的。

我将从编辑操作中删除 @post.build_location。该视图应该工作,因为它已经在寻找 postlocation,这与 @post.location

相同

编辑 您可能想要如下行为:

  • 如果 Post 有位置,在 Post
  • 的编辑中显示当前位置
  • 如果 Post 没有位置,在 Post
  • 的编辑中显示空白字段

为此,只有当 Post 没有 Location 时,您才需要在编辑操作中构建 Location 对象。

 def edit
    @category = Category.friendly.find(params[:category_id])
    @post = Post.find(params[:id])
    @post.build_location if @post.location.nil?
  end

这是您在编辑操作中需要的

当您调用 @post.build_location 时,它会从数据库中清除您的旧位置。

在 "When are objects saved?"

上查看 Rails 指南

例如:

a = Whole.new
a.save
a
=> #<Whole id: 2, name: "foo", created_at: "2015-09-02 05:15:15", updated_at: "2015-09-02 05:15:15">
a.part
=> nil
b = a.build_part
b.save
a.part
=> #<Part id: 1, name: nil, created_at: "2015-09-02 05:16:37", updated_at: "2015-09-02 05:16:37", whole_id: 2> 
c = a.build_part
=> #<Part id: nil, name: nil, created_at: nil, updated_at: nil, whole_id: 2>
Part.find_by(whole_id: 2)
=> nil

如果还没有,您也可以只建立一个新位置:

@post.build_location unless @post.location

更新控制器中的编辑方法。仅在 post 没有关联位置时构建实例。

@post.build_location if @post.location.blank?