У меня проблема с 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 я строил текст с атрибутами для проверки определенных вещей ... Но после этого построенный текст не был уничтожен, поэтому он был добавлен к текстам заказа.