Рельсы создаются с вложенными атрибутами. текстовое поле не появляется - PullRequest
1 голос
/ 14 июня 2019

Проблема: у меня нет вложенных полей_для текстового поля, я не уверен, что я сделал неправильно.

Цель: при создании записи переберите модель с предустановленными переменными и сохраните файл (тестирование с text_field) в таблице соединений, в которой сохраняются как предустановленные переменные, так и идентификатор записи формы

Модель:

class PrintLocation < ApplicationRecord
  has_many :shop_products, through: :shop_product_print_files
  has_many :shop_product_print_files
  accepts_nested_attributes_for :shop_product_print_files
end

class ShopProductPrintFile < ApplicationRecord
  belongs_to :shop_products
  belongs_to :print_locations
end

class ShopProduct < ApplicationRecord
    ...
  has_many :shop_product_print_files
  has_many :print_locations, through: :shop_product_print_files
  accepts_nested_attributes_for :print_locations
  accepts_nested_attributes_for :shop_product_print_files
    ...
end

Форма:

<%= form_for @shop_product do |f| %>
   <%= f.collection_select :product_id, @products, :id, :sku %>
   <% PrintLocation.all.each do |print_location| %>
     <%= print_location.title %>
        <%= f.fields_for :shop_product_print_files do |a| %>
           <%= a.text_field :print_file %>
        <% end %>
     <% end %>
   <%= f.submit %>
<% end %>

При этом текстовое поле не появляется, но print_location.title появляется. С этим нет ошибок.

Сохраняя @shop_product, я хочу иметь возможность перебирать возможные переменные print_location, которые определены, а затем для каждой возможной print_location, чтобы затем иметь возможность загрузить файл (text_field для тестирования ), а затем сохраните его в модели ShopProductPrintFile, которая имеет атрибуты shop_product_id и print_location_id и print_file.

Есть ли что-то, что я неправильно понимаю, как использовать fields_for?

Контроллер продуктов магазина:

Создать:

@shop_product = ShopProduct.new(shop_product_params)
shop = Shop.find(params["shop_product"]["shop_id"])
product = Product.find(params["shop_product"]["product_id"])    @shop_product.product_id = product.id
@shop_product.shop_id = shop.id
respond_to do |format|
   if @shop_product.save!
...

Обновление:

@shop_product = ShopProduct.find_by(store_variant_id: params["shop_product"]["store_variant_id"])
@product = Product.find(params["shop_product"]["product_id"])

Сильные параметры:

def shop_product_params
   params.require(:shop_product).permit(:product_id, :store_product_id, :shop_id, :store_variant_id, :sync, :shop_product_print_file_attributes[:id, :print_files, :print_location_ids => [], :shop_product_ids => []], {print_location_ids: []})
end

ОБНОВЛЕНИЕ 2:

Метод обновления и создания:

@shop_product.shop_product_print_files.build

Форма:

<% PrintLocation.all.each do |print_location| %>
  <%= print_location.title %>
    <%= f.fields_for :shop_product_print_files_attributes do |a| %>
       <%= a.text_field :print_file %>
       <%= a.hidden_field :print_location_id, value: print_location.id %>
       <%= a.hidden_field :shop_product_id, value: shop_product.id %>
    <% end %>
<% end %>

Титулы:

def shop_product_params
   params.require(:shop_product).permit(:shop_product_print_files_attributes => [:ids => [], :print_files => [], :print_location_ids => [], :shop_product_ids => []])
end

ошибка: Shop product print files shop products must exist Shop product print files print locations must exist

передаваемые параметры:

Parameters: {"utf8"=>"✓", "authenticity_token"=>"u/c103465uNCjF/trYrMleqxJ8b9wyLbU/vjPK4llYtCg/ODj92q5MN24==", "shop_product"=>{"sync"=>"1", "product_id"=>"3", "shop_product_print_files_attributes"=>{"print_file"=>"", "print_location_id"=>"6", "shop_product_id"=>"42"}, "store_product_id"=>"191234345", "store_variant_id"=>"15341234273", "id"=>"42"}, "commit"=>"Sync", "id"=>"42"}

Модели не изменились.

Печать файла в параметрах все еще пуста?

ОБНОВЛЕНИЕ 3:

** используя эту форму: благодаря @arieljuod **

<%= f.fields_for :shop_product_print_files do |ff| %>
    <%= ff.object.print_location.title # get the print location from the association %> 
    <%= ff.hidden_field :print_location_id # save the print_location_id as a hidden field %>
    <%= ff.file_field :print_file # file input %>
  <% end %>

с этим в новом и методе, охватывающем вид:

@shop_product = ShopProduct.new
PrintLocation.all.each{|p| @shop_product.shop_product_print_files.build(print_location: p)}

работает над созданием.

Проблема по-прежнему возникает из-за незнания идентификатора ShopProduct до тех пор, пока страница не загружается из-за API, и существует вероятность наличия нескольких идентификаторов на одной странице.

Я использую:

<% if @shop_products.find_by(store_variant_id: variant.id)  %>
<% shop_product = @shop_products.find_by(store_variant_id: variant.id)  %>
   <%= form_for shop_product do |f| %>
   ...

Что, variant происходит из цикла, определенного API:

<% @in_store_variants.each do |variant| %>

Теперь при использовании shop_products (с момента, когда shop_product уже существует от поиска по variant.id), fields_for не появится. Предполагая, что это потому, что нет никаких записей в отношении. Только если shop_product.shop_product_print_files существуют, они появятся.

На данный момент, насколько мне известно, единственное обходное решение состоит в том, чтобы сохранить все print_locations, но использовать логическое значение, для которого фактически активны, или выполнить поиск, для которого print_locations прикреплен идентификатор. Но я бы предпочел не делать это таким образом, а просто сохранить, какие print_locations выбраны при создании (выбрано путем загрузки print_file).

Чтобы «исправить» эту проблему, я:

  1. добавлено accepts_nested_attributes_for reject_if: proc { |attributes| attributes['print_file'].blank? }, которое не сохраняет ShopProductPrintFile, если в поле print_file не указано что-то ...

  2. используйте эту форму (2 формы в зависимости от того, существует или нет)

    <% if @shop_products.find_by(store_variant_id: variant.id)  %>
       <%= form_for shop_product do |f| %>
       <% PrintLocation.all.each{|p| shop_product.shop_product_print_files.build(print_location: p)} %>
       <%= f.fields_for :shop_product_print_files do |ff| %>
           <%= ff.object.print_location.title %>
          <%= ff.hidden_field :print_location_id %>
            <%= ff.text_field :print_file %>
       <% end %>
      <%= f.submit "Sync" %>
    <% end %>
    <% else %>
       <%= form_for @shop_product do |f| %>
       <% PrintLocation.all.each{|p| @shop_product.shop_product_print_files.build(print_location: p)} %>
       <%= f.fields_for :shop_product_print_files do |ff| %>
           <%= ff.object.print_location.title %>
           <%= ff.hidden_field :print_location_id %>
           <%= ff.text_field :print_file %>
       <% end %>
        ...
    

Проблема с 2 заключается в том, что у меня есть связанный PrintLocation 1,2,3, он покажет 9 полей, 1,2,3 готовы к обновлению и 6 готовы к созданию.

можно ли вызвать PrintLocation.all.each{|p| @shop_product.shop_product_print_files.build(print_location: p)} для уже созданных ShopProducts, для которых файл shop_product_print_file не существует относительно возможного местоположения печати. ​​

Так, например ... Создан ShopProduct с местом печати, 1,2,3 (из 6 возможных)

Теперь shop_product_print_location, где существует print_location, будет отображаться для обновления в форме, то есть 1,2 и 3. Как это можно сделать, чтобы остальные 3, которые не были созданы, теперь отображались для обновления ShopProduct и создания нового ShopProductPrintFile's ? так что можно обновить ShopProduct, чтобы иметь больше print_locations для модели shop_product_print_file.

Ответы [ 2 ]

1 голос
/ 14 июня 2019

У меня есть вложенные поля_для текстового поля, я не уверен, что я сделал неправильно.

Вы должны добавить эту строку в ваше действие создания

@shop_product = ShopProduct.new(shop_product_params)
@shop_product.shop_product_print_files.build #this one

Также измените shop_product_print_file_attributes на shop_product_print_files_attributes, чтобы избежать дальнейших ошибок.

0 голосов
/ 15 июня 2019

Вы должны указать rails, какой PrintLocation использовать на каждой итерации, поскольку у вашего объекта нет

<%= f.fields_for :shop_product_print_files, print_location do |a| %>

Я не совсем уверен, если это то, что вы хотите, но поле появится.

РЕДАКТИРОВАТЬ: так что, я думаю, вам нужно что-то вроде этого:

На контроллере

@shop_product = something_to_get_the_product
PrintLocation.all.each{|p| @shop_product.shop_product_print_files.build(print_location: p)}

Я предпочитаю делать это здесь, мне не нравится эта логика в представлении

Теперь у вас есть все возможные местоположения печати, предварительно созданные на объекте магазина

В форме

# note here the multipart option to allow files
<%= form_for @shop_product, multipart: true do |f| %>
  <%= f.collection_select :product_id, @products, :id, :sku %>

  <%= f.fields_for :shop_product_print_files do |ff| %>
    <%= ff.object.print_location.title # get the print location from the association %> 
    <%= ff.hidden_field :print_location_id # save the print_location_id as a hidden field %>
    <%= ff.file_field :print_file # file input %>
  <% end %>

  <%= f.submit %>
<% end %>
...