Объект Rails теряет значение параметров при его создании

У меня есть модель Product с некоторыми параметрами (цена, category_id, изображение и т. д.).

При создании нового продукта в частичной форме категория выбирается через select_tag, а изображение загружается через Carrierwave, загрузчик изображений. Плохие вещи случаются, когда я отправляю пользователя обрезать загруженное изображение в файле crop.html.erb. Там пользователь обрезает изображение, нажимает «Отправить», который использует путь в качестве обновления (не очень уверен, какой HTTP-протокол) и перенаправляется на страницу редактирования продукта, поскольку продукт каким-то образом потерял параметр category_id. Форма показывает ошибку при выборе категории (все остальные параметры из input_fields не теряются).

Мои попытки были похожи на определение метода crop и настройку категории там, но не повезло...

products_controller.rb:

  def edit
    @categories = Category.all
  end

  def create
    @product = Product.new(product_params)
    @product.category_id = params[:category_id]
    @product.user_id = current_user.id

    respond_to do |format|
      if @product.save
        if params[:product][:image].present?
          format.html { render :crop }
        else
          format.html { redirect_to @product, notice: 'Product was successfully created.' }
          format.json { render :show, status: :created, location: @product }
        end
      else
        format.html { render :new }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  def update
    @product.category_id = params[:category_id]

    respond_to do |format|
      if @product.update(product_params)
        if params[:product][:image].present?
          format.html { render :crop }
        else
          format.html { redirect_to @product, notice: 'Product was successfully updated.' }
          format.json { render :show, status: :ok, location: @product }

          @products = Product.all
          ActionCable.server.broadcast 'products',
            html: render_to_string('store/index', layout: false)
        end
      else
        format.html { render :edit }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

урожая.html.erb (в папке продуктов):

<%= image_tag @product.image_url(:large), id: "cropbox" %>

<h4>Preview</h4>
<div style="width:300px; height:200px; overflow:hidden;">
  <%= image_tag @product.image.url(:large), :id => "preview" %>
</div>

<%= form_for @product do |f| %>
  <% %w[x y w h].each do |attribute| %>
    <%= f.hidden_field "crop_#{attribute}" %>
  <% end %>
  <div class="actions">
    <%= f.submit "Crop" %>
  </div>
<% end %>

Я не пытался установить обратный вызов, в котором хранится category_id, но интересно, будет ли это хорошей идеей? Любая помощь? Спасибо!

РЕДАКТИРОВАТЬ - также добавить частичную форму, но она отлично работает - просто для вашего любопытства:

<%= form_for(product, hmtl: { multipart: true } ) do |f| %>
...
  <div class="field">
    <%= f.label :category %>
    <%= select_tag(:category_id, options_from_collection_for_select(Category.all, :id, :name, @product.category_id), include_blank: "Select Category") %>
  </div>

ОБНОВЛЕНИЕ

Журналы для этих действий:

Started GET "/products/new" for ::1 at 2016-12-15 09:03:31 +0200
Processing by ProductsController#new as HTML
  [1m[36mCart Load (0.4ms)[0m  [1m[34mSELECT  "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m  [["id", 5], ["LIMIT", 1]]
  [1m[36mCACHE (0.0ms)[0m  [1m[34mSELECT  "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m  [["id", 5], ["LIMIT", 1]]
  [1m[36mUser Load (2.0ms)[0m  [1m[34mSELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m  [["id", 1], ["LIMIT", 1]]
  Rendering products/new.html.erb within layouts/application
  [1m[36mCategory Load (0.4ms)[0m  [1m[34mSELECT "categories".* FROM "categories"[0m
  Rendered products/_form.html.erb (6.2ms)
  Rendered products/new.html.erb within layouts/application (11.2ms)
  [1m[36mCACHE (0.0ms)[0m  [1m[34mSELECT "categories".* FROM "categories"[0m
  [1m[36mLineItem Load (0.5ms)[0m  [1m[34mSELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = $1[0m  [["cart_id", 5]]
Completed 200 OK in 127ms (Views: 113.2ms | ActiveRecord: 3.3ms)


Started POST "/products" for ::1 at 2016-12-15 09:03:40 +0200
Processing by ProductsController#create as HTML
  Parameters: {"utf8"=>"✓", "authenticity_token"=>"eWZuqL6AqcN8wknjEL115ax9uBnpY4b9eP0o2xN2aPntd61YKyc4Ym1lUgjV1YrXfZbPr57HANXy7Kz5swCtlg==", "product"=>{"title"=>"kj", "description"=>"kj", "image"=>#<ActionDispatch::Http::UploadedFile:0x007fe40ba4abe0 @tempfile=#<Tempfile:/var/folders/dn/zq9x2jkd4856kwhfj5gbz2tc0000gn/T/RackMultipart20161215-3987-1adfacs.png>, @original_filename="Screen Shot 2016-12-05 at 09.14.48.png", @content_type="image/png", @headers="Content-Disposition: form-data; name=\"product[image]\"; filename=\"Screen Shot 2016-12-05 at 09.14.48.png\"\r\nContent-Type: image/png\r\n">, "price"=>"98", "quantity"=>"98"}, "category_id"=>"1", "commit"=>"Create Product"}
  [1m[36mCart Load (0.3ms)[0m  [1m[34mSELECT  "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m  [["id", 5], ["LIMIT", 1]]
  [1m[36mCACHE (0.0ms)[0m  [1m[34mSELECT  "carts".* FROM "carts" WHERE "carts"."id" = $1 LIMIT $2[0m  [["id", 5], ["LIMIT", 1]]
  [1m[36mUser Load (0.7ms)[0m  [1m[34mSELECT  "users".* FROM "users" WHERE "users"."id" = $1 ORDER BY "users"."id" ASC LIMIT $2[0m  [["id", 1], ["LIMIT", 1]]
  [1m[35m (0.3ms)[0m  [1m[35mBEGIN[0m
  [1m[36mCategory Load (0.3ms)[0m  [1m[34mSELECT  "categories".* FROM "categories" WHERE "categories"."id" = $1 LIMIT $2[0m  [["id", 1], ["LIMIT", 1]]
  [1m[35mSQL (1.0ms)[0m  [1m[32mINSERT INTO "products" ("title", "description", "price", "quantity", "created_at", "updated_at", "category_id", "user_id", "image") VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9) RETURNING "id"[0m  [["title", "kj"], ["description", "kj"], ["price", #<BigDecimal:7fe40ccf9110,'0.98E2',9(18)>], ["quantity", 98], ["created_at", 2016-12-15 07:03:41 UTC], ["updated_at", 2016-12-15 07:03:41 UTC], ["category_id", "1"], ["user_id", 1], ["image", "Screen_Shot_2016-12-05_at_09.14.48.png"]]
  [1m[35m (3.1ms)[0m  [1m[35mCOMMIT[0m
  Rendering products/crop.html.erb within layouts/application
  Rendered products/crop.html.erb within layouts/application (3.1ms)
  [1m[36mCategory Load (0.7ms)[0m  [1m[34mSELECT "categories".* FROM "categories"[0m
  [1m[36mLineItem Load (0.3ms)[0m  [1m[34mSELECT "line_items".* FROM "line_items" WHERE "line_items"."cart_id" = $1[0m  [["cart_id", 5]]
Completed 200 OK in 957ms (Views: 127.8ms | ActiveRecord: 6.7ms)

Итак, я заметил, что он отображает products/crop.html.erb без определенного идентификатора, поэтому я добавил в свои маршруты:

  resources :products do
    get 'crop', on: :member
  end

И products_controller создает действие:

...
    respond_to do |format|
      if @product.save
        if params[:product][:image].present?
          format.html { render crop_product_path(@product) }
        else
...

Все та же ошибка, что нужно выбрать категорию. И на заметку - если просто зайти в редактирование товара (а не из действия crop), то категория сидит там как положено...


person Julius    schedule 14.12.2016    source источник
comment
Попробуйте добавить hidden_field вместо category_id в представление crop.html. и установите его на @product.category_id. Затем вы можете позже получить значение в действии update   -  person Kkulikovskis    schedule 20.12.2016
comment
Хм, хороший улов, но затем я получаю undefined method {:category_id=>"1"}'... Пытался определить продукт в действии урожая в контроллере продуктов... Скрытое поле: <%= f.hidden_field :category_id => @product.category_id %>   -  person Julius    schedule 20.12.2016
comment
если вы поместите скрытое поле внутри формы, оно будет находиться под product, поэтому, чтобы получить category_id в действии обновления, оно будет под params[:product][:category_id]   -  person Kkulikovskis    schedule 20.12.2016
comment
и посмотрите, как установить скрытое поле в apidock.com/rails/ActionView/Helpers /FormHelper/скрытое_поле   -  person Kkulikovskis    schedule 20.12.2016
comment
Это работает! Большое спасибо. Не могли бы вы опубликовать как ответ? Так что я мог принять это   -  person Julius    schedule 20.12.2016
comment
готово :) Рад, что смог помочь   -  person Kkulikovskis    schedule 20.12.2016
comment
Рада получить :)   -  person Julius    schedule 20.12.2016


Ответы (1)


Поскольку форма отправляет только собранные параметры, которые в ней определены, вам следует добавить скрытое поле, чтобы установить category_id в представлении crop.html.

<%= image_tag @product.image_url(:large), id: "cropbox" %>

<h4>Preview</h4>
<div style="width:300px; height:200px; overflow:hidden;">
  <%= image_tag @product.image.url(:large), :id => "preview" %>
</div>

<%= form_for @product do |f| %>
  <% %w[x y w h].each do |attribute| %>
    <%= f.hidden_field "crop_#{attribute}" %>
  <% end %>
  <%= f.hidden_field :category_id %>
  <div class="actions">
    <%= f.submit "Crop" %>
  </div>
<% end %>

Теперь, когда вы отправите форму, вы получите category_id на сервере в params[:product][:category_id]

person Kkulikovskis    schedule 20.12.2016