简单表单的simple_fields_for复制了我的记录

时间:2019-06-07 07:46:20

标签: ruby-on-rails simple-form

我遇到了simple_form问题。我有一个模型Order,可以有许多textsText模型可以具有 OR 文本内容或附加的文档。

我希望可以更新@order并添加用户想要的任意数量的文本。在视图中,呈现了我的表单,然后在两个不同的部分中显示了一个simple_fields_for :texts

show.slim:

.card
  = simple_nested_form_for(@order, url: steps_order_texts_url, html: { id: 'order-form' }) do |f|
    .card-body
      .row.mx-1
        .col
          = render('filedownloader', f: f)
          = render('copytext', f: f)

    .card-footer.fast-card-footer
        = button_tag(type: 'submit', class: 'btn btn-primary btn-lg fast-btn', data: { disable_with: 'Please wait...' }) do
          | Next
          =< fa_icon('far', 'angle-right')

_filedownloader.slim:

.text-upload-content-wrapper
  .filedownloader-wrapper-bottom
    - secureId = SecureRandom.hex
    .d-flex.flex-column.caption id="#{secureId}"
      .d-flex.align-items-center
        label.btn.btn-lg.btn-primary-dark.text-nowrap.filedownloader-custom-button for="text_document_#{secureId}"
          | Choose a file
        = f.simple_fields_for(:texts, @order.texts.build) do |ff|
          = ff.input(\
            :document,
            label: false,
            error: false,
            input_html: { hidden: true,
                          id: "text_document_#{secureId}",
                          direct_upload: true)

  .filedownloader-divider

  .filedownloader-wrapper-footer
    .d-inline-flex.align-items-center
      span.filedownloader-addfile
        = fa_icon('fal', 'plus-circle')
        | Add a file

_copytext.slim:

.text-copy-content-wrapper
  .filedownloader-copy-wrapper-bottom
    = hidden_field_tag(:id, @order.id)
    #recurring-texts
      = f.simple_fields_for(:texts) do |ff|
        - unless ff.object.persisted? && ff.object.content.blank?
          .order-form-text
            = ff.input( \
                :content,
                input_html: { \
                class: 'form-control order-form-text-description',
                rows: 4,},
                required: true)

            .d-flex.justify-content-end
              = ff.link_to_remove( \
              t('orders.remove_text'),
              class: 'btn btn-danger btn-sm',
              data: { confirm: "Are you sure?" })

    = f.link_to_add( \
      "#{fa_icon('far', 'plus-circle')} Add a text".html_safe,
      :texts,
      data: { target: '#recurring-texts' },
      class: 'btn btn-primary-dark btn-lg')

问题在于,当我提交表单时,我的记录是重复的。我以为是因为有两个simple_fields_for :texts,但是即使只有一个,文本也是重复的。另外,如果我尝试编辑文本,Rails会尝试创建具有相同ID的文本(因此会引发错误),而不是更新记录(当然id中允许texts_attributes )。

这是我创建一个文本时的日志,您可以看到ActiveRecord插入了两个文本:

Started PATCH "/steps/orders/311/texts" for ::1 at 2019-06-07 09:43:21 +0200
09:43:21 server.1 | Processing by Steps::TextsController#update as HTML
09:43:21 server.1 |   Parameters: {"utf8"=>"✓", "authenticity_token"=>"eHZ1561Ly1SvWGdcj5jXasb+zLaA2PO+alY57K2ASaqyz5UwiACT9pclrSgdDfAnRjd+Pm0n9Ordk6JJb2WGHQ==", "file_upload_method_upload"=>"upload", "file_upload_method_copy"=>"copy", "order"=>{"texts_attributes"=>{"1"=>{"content"=>"I'm creating only one text", "_destroy"=>"false"}}}, "button"=>"", "order_id"=>"311"}
09:43:21 server.1 |   User Load (1.2ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2  [["id", 2], ["LIMIT", 1]]
09:43:21 server.1 |   ↳ /Users/robin/.rvm/gems/ruby-2.5.1/gems/activerecord-5.2.3/lib/active_record/log_subscriber.rb:98
09:43:21 server.1 |   Order Load (1.2ms)  SELECT  "orders".* FROM "orders" WHERE "orders"."id" = $1 LIMIT $2  [["id", 311], ["LIMIT", 1]]
09:43:21 server.1 |   ↳ app/controllers/steps/base_controller.rb:17
09:43:21 server.1 |   User Load (0.4ms)  SELECT  "users".* FROM "users" WHERE "users"."id" = $1 LIMIT $2  [["id", 2], ["LIMIT", 1]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:57
09:43:21 server.1 |   Profile Load (0.5ms)  SELECT  "profiles".* FROM "profiles" WHERE "profiles"."user_id" = $1 LIMIT $2  [["user_id", 2], ["LIMIT", 1]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:57
09:43:21 server.1 |    (0.3ms)  BEGIN
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Category Load (0.4ms)  SELECT  "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2  [["id", 424], ["LIMIT", 1]]
09:43:21 server.1 |   ↳ app/services/pricing.rb:10
09:43:21 server.1 |   TextQuality Load (0.4ms)  SELECT  "text_qualities".* FROM "text_qualities" WHERE "text_qualities"."id" = $1 LIMIT $2  [["id", 1], ["LIMIT", 1]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Text Load (0.6ms)  SELECT "texts".* FROM "texts" WHERE "texts"."order_id" = $1 ORDER BY "texts"."created_at" ASC  [["order_id", 311]]
09:43:21 server.1 |   ↳ app/models/order.rb:124
09:43:21 server.1 |    (0.3ms)  SELECT SUM("texts"."word_number") FROM "texts" WHERE "texts"."order_id" = $1  [["order_id", 311]]
09:43:21 server.1 |   ↳ app/models/order.rb:304
09:43:21 server.1 |   Order Update (0.7ms)  UPDATE "orders" SET "updated_at" = $1, "real_words_count" = $2 WHERE "orders"."id" = $3  [["updated_at", "2019-06-07 07:43:21.334874"], ["real_words_count", 0], ["id", 311]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Text Create (0.7ms)  INSERT INTO "texts" ("order_id", "content", "created_at", "updated_at", "word_number") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["order_id", 311], ["content", "I'm creating only one text"], ["created_at", "2019-06-07 07:43:21.340588"], ["updated_at", "2019-06-07 07:43:21.340588"], ["word_number", 5]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Order Update All (0.5ms)  UPDATE "orders" SET "texts_count" = COALESCE("texts_count", 0) + 1 WHERE "orders"."id" = $1  [["id", 311]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Text Update (0.4ms)  UPDATE "texts" SET "word_number" = $1 WHERE "texts"."id" = $2  [["word_number", 5], ["id", 1374]]
09:43:21 server.1 |   ↳ app/models/text.rb:323
09:43:21 server.1 |   Text Create (0.3ms)  INSERT INTO "texts" ("order_id", "content", "created_at", "updated_at", "word_number") VALUES ($1, $2, $3, $4, $5) RETURNING "id"  [["order_id", 311], ["content", "I'm creating only one text"], ["created_at", "2019-06-07 07:43:21.346443"], ["updated_at", "2019-06-07 07:43:21.346443"], ["word_number", 5]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Order Update All (0.3ms)  UPDATE "orders" SET "texts_count" = COALESCE("texts_count", 0) + 1 WHERE "orders"."id" = $1  [["id", 311]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |   Text Update (0.3ms)  UPDATE "texts" SET "word_number" = $1 WHERE "texts"."id" = $2  [["word_number", 5], ["id", 1375]]
09:43:21 server.1 |   ↳ app/models/text.rb:323
09:43:21 server.1 |    (0.7ms)  COMMIT
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:12
09:43:21 server.1 |    (0.1ms)  BEGIN
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:17
09:43:21 server.1 |    (0.3ms)  SELECT SUM("texts"."word_number") FROM "texts" WHERE "texts"."order_id" = $1  [["order_id", 311]]
09:43:21 server.1 |   ↳ app/models/order.rb:304
09:43:21 server.1 |   Order Update (0.5ms)  UPDATE "orders" SET "updated_at" = $1, "real_words_count" = $2 WHERE "orders"."id" = $3  [["updated_at", "2019-06-07 07:43:21.355083"], ["real_words_count", 10], ["id", 311]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:17
09:43:21 server.1 |    (0.7ms)  COMMIT
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:17
09:43:21 server.1 |   User Load (1.9ms)  SELECT  "users".id, "users".id, COUNT("texts".id)*1 AS count, MAX("users".assigned_texts_count) AS assigned_texts_count FROM "users" LEFT JOIN "candidacies" AS candidacies ON "users".id = candidacies.user_id LEFT JOIN "texts" AS texts ON "candidacies".id = texts.candidacy_id AND (texts.aasm_state = 'assigned') GROUP BY "users"."id" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1000]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |    (0.2ms)  BEGIN
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |    (0.2ms)  COMMIT
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |   User Load (0.9ms)  SELECT  "users".id, "users".id, COUNT("texts".id)*1 AS count, MAX("users".accepted_texts_count) AS accepted_texts_count FROM "users" LEFT JOIN "candidacies" AS candidacies ON "users".id = candidacies.user_id LEFT JOIN "texts" AS texts ON "candidacies".id = texts.candidacy_id AND (texts.aasm_state = 'accepted') GROUP BY "users"."id" ORDER BY "users"."id" ASC LIMIT $1  [["LIMIT", 1000]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |    (0.1ms)  BEGIN
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |    (0.2ms)  COMMIT
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |   Order Load (0.8ms)  SELECT  "orders".id, "orders".id, COUNT("texts".id)*1 AS count, MAX("orders".texts_count) AS texts_count FROM "orders" LEFT JOIN "texts" AS texts ON "orders".id = texts.order_id GROUP BY "orders"."id" ORDER BY "orders"."id" ASC LIMIT $1  [["LIMIT", 1000]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |    (0.2ms)  BEGIN
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |   Order Update All (0.4ms)  UPDATE "orders" SET texts_count = 2 WHERE "orders"."id" = $1  [["id", 311]]
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 |    (0.3ms)  COMMIT
09:43:21 server.1 |   ↳ app/controllers/steps/texts_controller.rb:19
09:43:21 server.1 | Redirected to http://localhost:3000/steps/orders/311/instructions
09:43:21 server.1 | Completed 302 Found in 73ms (ActiveRecord: 16.1ms)

我们可以看到以下内容:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"eHZ1561Ly1SvWGdcj5jXasb+zLaA2PO+alY57K2ASaqyz5UwiACT9pclrSgdDfAnRjd+Pm0n9Ordk6JJb2WGHQ==", "order"=>{"texts_attributes"=>{"1"=>{"content"=>"I'm creating only one text", "_destroy"=>"false"}}}, "button"=>"", "order_id"=>"311"}

只有一个文本,所以我真的不知道是什么问题... 有想法吗?

非常感谢

编辑:

steps / texts_controller.rb:

# frozen_string_literal: true

module Steps
  class TextsController < BaseController
    before_action(:redirect_unless_authorized)

    def show
    end

    def update
      if @order.update(order_params)
        if @order.texts.none? { |text| text.content.present? } && !@order.documents?
          flash.now.alert = t('.add_texts')
          render(:show)
        else
          @order.update!(creation_step: 'instructions')

          Text.counter_culture_fix_counts
          jump_to(:instructions)
        end
      else
        flash.now.alert = @order.errors.full_messages.join('. ') if @order.errors.messages.any?
        render(:show)
      end
    end

    def destroy
      @text = @order.texts.find_by(id: params[:text_id])
      @text.destroy

      respond_to do |format|
        format.json { head :no_content }
        format.js   { render layout: false }
      end
    end

  private

    def order_params
      params.require(:order).permit(texts_attributes: %i[id document content _destroy])
    end

    def redirect_unless_authorized
      return if admin_creates_for_user?

      step = next_step
      return unless step

      jump_to(step, what_params)
    end

    def next_step
      if !@order.paid?
        :payment
      elsif @order.user.profile&.invalid? && @order.paid?
        :profile
      end
    end
  end
end

编辑2: 我在更新前添加了一个byebug,然后检查(以防万一)order_params:

<ActionController::Parameters {"texts_attributes"=><ActionController::Parameters {"1"=><ActionController::Parameters {"content"=>"Hello world", "_destroy"=>"false"} permitted: true>} permitted: true>} permitted: true>

好的,只有一个文本。现在:

order = Order.new(order_params)
order.texts.size
#=> 2
order.pluck(:content)
#=> ['Hello world', 'Hello world']

... Wtf?

解决方案: 好,我不好在我的订单模型中,我的reject_if上有一个accepts_nested_attributes_for。在这个reject_if中,我正在构建带有属性的文本以测试某些东西。但是构建的文本之后并没有被销毁,因此将其添加到订单的文本中。

0 个答案:

没有答案