Rails множественные вложенные формы - PullRequest
1 голос
/ 24 октября 2019

Это мой первый проект на Rails, и я пытаюсь создать форму для добавления продуктов, которые могут иметь несколько пар свойств и значений свойств. Я ознакомился с несколькими учебными пособиями и просмотрел несколько ответов, касающихся вложенных форм, но я застрял на том, действительно ли информация сохраняет и отображает информацию. Я использовал самоцвет Cocoon для динамического создания дополнительных пар имени и значения свойства. Я попытался использовать простую вложенную форму, чтобы убедиться, что я правильно структурировал модели - это код ниже. Я включил соответствующий код из моего проекта ниже. Любая помощь с благодарностью!

controllers / products_controller.erb

class ProductsController < ApplicationController
  def index
    @products = Product.all
    gon.products = Product.all
  end

  def show
    @product = Product.find(params[:id])
    @properties = Product.find(params[:id])
  end

  def new
    @product = Product.new
    @properties = @product.properties.build
    @product_properties = @properties.product_properties.build
  end

  def create
    @product = Product.new(product_params)

    if @product.save
    redirect_to products_path,
    notice: 'The product was successfully created.'
    else
      render 'new'
    end
  end

  private
  def product_params
    params.require(:product).permit(:name, :upc, :available_on,
      :properties_attributes => [:property_name,
        :product_properties_attributes => [:value]
        ])
  end
  def get_property
    @property = Property.find(params[:property_id])
  end
end

models / product.rb

class Product < ApplicationRecord
  has_many :properties
  has_many :product_properties,
           :through => :properties
  accepts_nested_attributes_for :properties
  accepts_nested_attributes_for :product_properties
  attr_accessor :properties_attributes,
                :product_properties_attributes

  validates :name, :upc, :available_on, presence: true
  validates :name, :upc, uniqueness: true
  validates :upc, numericality: { only_integer: true }

  validates :name, length: { maximum: 1024,
    too_long: "%{count} characters is the maximum allowed" }


  validate :check_length

  def check_length
    unless upc.size == 10 or upc.size == 12 or upc.size == 13
      errors.add(:upc, "length must be 10, 12, or 13 characters")
    end
  end

  validate :expiration_date_cannot_be_in_the_past

  def expiration_date_cannot_be_in_the_past
    errors.add(:available_on, "must be a future date") if
      !available_on.blank? and available_on < Date.today
  end

end

models / property.rb

class Property < ApplicationRecord
  belongs_to :product
  has_many :product_properties
  accepts_nested_attributes_for :product_properties
  attr_accessor :property_name,
                :value,
                 :product_properties_attributes


  validates :property_name, presence: true
  validates :property_name, uniqueness: true
  validates :property_name, length: { maximum: 255,
    too_long: "%{count} characters is the maximum allowed" }
end

models / product_property.rb

class ProductProperty < ApplicationRecord
  belongs_to :property
  belongs_to :product
  attr_accessor :value

  validates :value, presence: true
  validates :value, length: { maximum: 255,
    too_long: "%{count} characters is the maximum allowed" }

end

views / products / new.html.erb

<h1>New Product</h1>
<%= form_with scope: @product, url: products_path, local: true do |f| %>

<% if @product.errors.any? %>
   <div id="error_explanation">
     <h2>
       <%= pluralize(@product.errors.count, "error") %> prohibited
       this product from being saved:
     </h2>
     <ul>
       <% @product.errors.full_messages.each do |msg| %>
         <li><%= msg %></li>
       <% end %>
     </ul>
   </div>
 <% end %>

  <p>
    <strong>Name</strong><br>
    <%= f.text_field :name %>
  </p>

  <p>
    <strong>UPC</strong><br>
    <%= f.text_field :upc %>
  </p>

  <p>
    <strong>Available On</strong><br>
    <%= f.date_field :available_on %>
  </p>

  <h3>Properties</h3>
  <div id='properties'>
    <%= f.fields_for (:properties) do |property| %>
      <%= property.fields_for (:product_properties) do |product_property| %>
      <p>
        <strong>Property Name</strong><br>
        <%= property.text_field :property_name %>
      </p>

      <p>
        <strong>Property Value</strong><br>
        <%= product_property.text_field :value %>
      </p>
     <% end %>
<% end %>
  </div>


  <p>
    <%= f.submit "Add Product" %>
  </p>
<% end %>

views / products / index.html.erb

<h1>Products</h1>

<%= link_to 'New Product', new_product_path %>

<div id="search"></div>

<table>
  <tr>
    <th>Name</th>
    <th>UPC</th>
    <th>Available On</th>
    <th></th>
  </tr>

  <% @products.each do |product| %>
    <tr>
      <td><%= product.name %></td>
      <td><%= product.upc %></td>
      <td><%= product.available_on %></td>
       <% product.properties.each do |property| %>
       <td><%= property.property_name %></td>
       <% end %>
      <td><%= link_to 'Details', product_path(product) %></td>
    </tr>
  <% end %>
</table>

1 Ответ

0 голосов
/ 27 октября 2019

Новый form_with, который сочетает в себе предыдущие form_for и form_tag, делает его, с одной стороны, довольно мощным, но иногда очень сбивающим с толку. То, что раньше было просто form_for @product, теперь у вас есть для записи

form_with model: @product, local: true do |f|

Использование scope: просто использует @product в качестве префикса и фактически не будет повторяться илииспользуйте @product для поиска ассоциаций, поэтому мы не видим ни property_attributes, ни неявного поля id, даже если у вас правильно есть accepts_nested_attributes (поле _destroy будет добавлено с помощью кокона link_to_remove_association - если вы захотите вернуться к возможности динамически добавлять / удалять вложенные элементы).

...