simple_fields_for простой формы дублирует мою запись - PullRequest
0 голосов
/ 07 июня 2019

У меня проблема с simple_form.У меня есть модель Order, которая может иметь много texts.Модель Text может иметь текстовое содержимое ИЛИ прикрепленного документа.

Я имею в виду обновить @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 разрешено в 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 / text_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: Я добавил бибаг до обновления, затем я проверил (на всякий случай) 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?

РЕШЕНИЕ: Хорошо, плохо.В моей модели Order у меня было reject_if на моем accepts_nested_attributes_for.В этом reject_if я строил текст с атрибутами для проверки определенных вещей ... Но после этого построенный текст не был уничтожен, поэтому он был добавлен к текстам заказа.

...