rails nested_form 的问题

Problems with rails nested_form

大家好,我有一个问题让我无法入睡,我是 Rails 的新手,我想创建一个电子商务,我有产品,每个产品都可以有更多而不是一张图片,所以我使用 nested_forms 来创建一对多关系。显然,如果将它们上传到服务器,但会出现此问题:

我有这个代码:

product.rb

class Product < ApplicationRecord
 has_many :imagenes_productos
   accepts_nested_attributes_for :imagenes_productos, allow_destroy: true
 #paperclip para subir imagenes
 has_attached_file :imagenPrincipal, style: {medium: "1280x720", thumb:"800x600"}
 validates_attachment_content_type :imagenPrincipal, content_type: /\Aimage\/.*\z/
end

imagenes_producto.rb

class ImagenesProducto < ApplicationRecord
 belongs_to :product
end

_form.erb

<%= javascript_include_tag "application", "nested_form" %>


<div id="principalNuevoProducto">
  <div id="centradoNuevoProducto">
    <%= nested_form_for(@product) do |form| %>
      <% 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 |message| %>
            <li><%= message %></li>
          <% end %>
          </ul>
        </div>
      <% end %>

    <div id="izquierdaNuevoProducto">
      <div id="detallesProducto">
        <h2 id="subtitulosNuevoProducto">Detalles del producto</h2>
        <div id="contenidoDetallesProducto">
          <%= form.text_field :nombre, id: :product_nombre, placeholder: "Nombre de tu producto" %>
          <%= form.text_area :descripcionBreve, id: :product_descripcionBreve, placeholder: "Escribe una descripción breve sobre tu producto o servicio..." %>
            <div id="contenedorFileField">
              <p>Añadir imagen principal:</p>
              <%= form.file_field :imagenPrincipal, class:"upload" %>
            </div>
            <div id="contenedorYoutubeURL">
              <p>URL de video de Youtube:</p>
              <%= form.text_field :URLvideo, id: :product_URLvideo, placeholder: 'https://www.youtube.com/watch?v=-1111111' %>
            </div>
            <fieldset id="tareas">
              <p>Añadir imágenes secundarias</p>
              <%= form.fields_for :imagenes_productos do |imagenes_form| %>
                <%= imagenes_form.file_field :imagen %>

                <%= imagenes_form.link_to_remove "Eliminar esta imagen" %>
              <% end %>
              <p><%= form.link_to_add "Agregar una imagen", :imagenes_productos %></p>
            </fieldset>
        </div> 
      </div>  

      <div id="descripcionDetallada">
        <h2 id="subtitulosNuevoProducto">Decripción detallada</h2>
        <div id="editor"></div>
        <%= form.hidden_field :descripcionDetallada, id: :product_descripcionDetallada %>
      </div>

      <div id="inventario">
        <h2 id="subtitulosNuevoProducto">Inventario</h2>
        <div id="contenidoInventario">
          <p>
            ¿Desea manejar inventario de este producto?
          </p>
          <%= form.select(:manejarInventario, ['Si', 'No'], {}, {:class => 'manejarInventario'}) %>
          <p id="cantidadProductos">Cantidad de productos disponibles</p>
          <%= form.text_field :stock, placeholder:'0', id:'stock' %>
        </div>
      </div>

      <div id="detallesCompra">
        <h2 id="subtitulosNuevoProducto">Detalles de compra</h2>
        <div id="contenidoDetallesCompra">
          <div id="izquierdaDetallesCompra">
             <%= form.text_field :precioNormal, id: :product_precioNormal, placeholder:'Precio', class:'fieldsDetallesCompra' %>
             <p>
               Seleccione cuando comenzará la oferta:
             </p>
             <%= form.datetime_select(:inicioOferta, prompt: { day: 'Día', month: 'Mes', year: 'Año', hour: 'Hora', minute:'Minutos' }, order: [:day, :month, :year], start_year: 2017) %>
             <%= form.text_field :diasAnticipacion, id: :product_diasAnticipacion, placeholder: 'Días de anticipación para entrega de resultado', class:'fieldsDetallesCompra' %>
          </div>
          <div id="derechaDetallesCompra">
            <%= form.text_field :precioOferta, id: :product_precioOferta, placeholder: 'Precio de oferta', class:'fieldsDetallesCompra' %>
            <p>
               Seleccione cuando terminará la oferta:
             </p>
            <%= form.datetime_select(:terminoOferta, prompt: { day: 'Día', month: 'Mes', year: 'Año', hour: 'Hora', minute:'Minutos' }, order: [:day, :month, :year], start_year: 2017) %>
            <%= form.text_field :entregaResultados, id: :product_entregaResultados, placeholder: 'Días para entrega de resultados', class:'fieldsDetallesCompra' %>
          </div>
          <p id="preguntaDetallesCompra">¿Permite pedidos con menor tiempo de anticipación? De ser así, ¿Cuánto aumenta el costo?</p>
          <%= form.select(:menorAnticipacion, options_for_select([['Acepto con retraso', 1],['No acepto con retraso', 0]]), {}, {:class => 'anticipacion_field'}) %>
          <%= form.select(:diasAtrasoAnticipacion, options_for_select([['1 dia anticipación', 1],['2 días anticipación', 2],['3 dias anticipación', 3],['4 dias anticipación', 4],['5 dias anticipación', 5], ['6 dias anticipación', 6],['7 dias anticipación', 7], ['8 dias anticipación', 8], ['9 dias anticipación', 9],['10 dias anticipación', 10], ['11 dias anticipación', 11], ['12 dias anticipación', 12], ['13 dias anticipación', 13], ['14 dias anticipación', 14], ['15 dias anticipación', 15], ['16 dias anticipación', 16], ['17 dias anticipación', 17], ['18 dias anticipación', 18], ['19 dias anticipación', 19], ['20 dias anticipación', 20], ['21 dias anticipación', 21], ['22 dias anticipación', 22], ['23 dias anticipación', 23], ['24 dias anticipación', 24], ['25 dias anticipación', 25], ['26 dias anticipación', 26], ['27 dias anticipación', 27], ['28 dias anticipación', 28], ['29 dias anticipación', 29], ['Un mes', 30], ['Un mes y una semana', 37], ['Un mes y dos semanas', 45], ['Un mes y tres semanas', 52], ['Dos meses', 60]]), {}, {:class => 'atrasoAnticipacion_field'}) %>
          <%= form.text_field :aumentoAtrasoAnticipacion, id: :product_aumentoAtrasoAnticipacion, placeholder: '100.00' %>
          <p id="tituloMetodosPago">Métodos de pago</p>
          <p id="pmetodos">Indique hasta en cuantos pagos podrá liquidar el cliente</p>
          <%= form.select(:numeroPagos, options_for_select([['1 pago', 1], ['3 pagos', 3], ['6 pagos', 6], ['9 pagos', 9], ['12 pagos', 12]]), {}, {:class => 'numeroPagos_field'}) %>
          <p id="pmetodos">Indique con cuantos días de anticipación debe estar liquidado el total de la compra</p>
          <%= form.select(:diasAnticipoLiquidacion, options_for_select([['1 dia anticipación', 1],['2 días anticipación', 2],['3 dias anticipación', 3],['4 dias anticipación', 4],['5 dias anticipación', 5], ['6 dias anticipación', 6],['7 dias anticipación', 7], ['8 dias anticipación', 8], ['9 dias anticipación', 9],['10 dias anticipación', 10], ['11 dias anticipación', 11], ['12 dias anticipación', 12], ['13 dias anticipación', 13], ['14 dias anticipación', 14], ['15 dias anticipación', 15], ['16 dias anticipación', 16], ['17 dias anticipación', 17], ['18 dias anticipación', 18], ['19 dias anticipación', 19], ['20 dias anticipación', 20], ['21 dias anticipación', 21], ['22 dias anticipación', 22], ['23 dias anticipación', 23], ['24 dias anticipación', 24], ['25 dias anticipación', 25], ['26 dias anticipación', 26], ['27 dias anticipación', 27], ['28 dias anticipación', 28], ['29 dias anticipación', 29], ['Un mes', 30], ['Un mes y una semana', 37], ['Un mes y dos semanas', 45], ['Un mes y tres semanas', 52], ['Dos meses', 60]]), {}, {:class => 'anticipacionLiquidacion_field'}) %>
          <p id="pmetodos">¿Permitirá a sus clientes manejar pagos libres? De lo contrario se manejarán pagos iguales.</p>
          <%= form.select(:permitePagosLibres, ['Si', 'No'], {}, {:class => 'pagosLibres_field'}) %>
        </div>
      </div>


    </div> <!-- Aqui cierra izquierdaNuevoProducto -->
    
    <div id="derechaNuevoProducto">
      <div id="publicarProducto">
        <h2 id="subtitulosNuevoProducto">Publicar producto o servicio</h2>
        <div id="contenidoPublicar">
          <div id="botonVistaPrevia">
            <p style="float: left;">Vista previa</p>
            <img src="/assets/eye.png" style="float: left;">
          </div>
          <%= form.select(:visible, ['Visible', 'Oculto'], {}, {:class => 'visible_field'}) %>
          <div id="botonesPublicarProducto">
            <div class="boton-publicar gris">
              <p>Cancelar</p>
            </div>
            <%= form.submit 'Publicar', :class => 'boton-publicar azul' %>
          </div>
        </div>
      </div>
      <!-- Modificar -->
      <div id="tipoEvento">
        <h2 id="subtitulosNuevoProducto">Tipo de evento</h2>
        <div id="contenidoTipoEvento">
          <p>Categoria</p>
          <%= form.select(:categoria, ['Fotografía y video', 'Invitaciones', 'Cabinas de fotos', 'Spa', 'Pasteleria', 'Estéticas', 'Letras gigantes', 'Organizadores de eventos', 'Tuxedos', 'Renta de autos o transporte', 'Decoración y mantelería', 'Coctelería/shots/licores', 'Grupos musicales o djs', 'Agencia de viajes', 'Salones ', 'Vestidos', 'Florerias', 'Candy bar', 'Coreografias', 'Animación','Guarderías para eventos', 'Religiosos', 'Servicios banquetes y alimentos']) %>
        </div>
      </div>
      <div id="lugarEntrega">
        <h2 id="subtitulosNuevoProducto">Lugar de entrega</h2>
        <div id="contenidoLugarEntrega">
          <p>Escribe el lugar de entrega</p>
          <%= form.text_field :lugarEntrega, placeholder:'Ej. A domicilio o calle Prime #3125', id: :product_lugarEntrega %>
        </div>
      </div>
      <div id="duracionServicio">
        <h2 id="subtitulosNuevoProducto">Duración del servicio</h2>
        <div id="contenidoDuracionServicio">
          <p>Si estás ofreciendo un servicio y no un producto específica la duración de tu servicio: </p>
          <%= form.select(:duracionServicio, ['00:30:00', '01:00:00', '01:30:00', '02:00:00', '02:30:00', '03:00:00', '03:30:00', '04:00:00', '04:30:00', '05:00:00', '05:30:00', '06:00:00', '06:30:00', '07:00:00', '07:30:00', '08:00:00', '08:30:00', '09:00:00', '09:30:00', '10:00:00', '10:30:00', '11:00:00', '11:30:00', '12:00:00', '12:30:00', '13:00:00', '13:30:00', '14:00:00', '14:30:00', '15:00:00', '15:30:00', '16:00:00', '16:30:00', '17:00:00', '17:30:00', '18:00:00', '18:30:00', '19:00:00', '19:30:00', '20:00:00', '20:30:00', '21:00:00', '21:30:00', '22:00:00', '22:30:00', '23:00:00', '23:30:00', '24:00:00'], {}, {:class => 'servicio_field'}) %> hrs
          
        </div>
      </div>

    </div>
    <% end %>
  </div>
</div>

products_controller.rb

class ProductsController < ApplicationController
  before_action :set_product, only: [:show, :edit, :update, :destroy]

  # GET /products
  # GET /products.json
  def index
    @products = Product.all
  end

  # GET /products/1
  # GET /products/1.json
  def show
  end

  # GET /products/new
  def new
    @product = Product.new
  end

  # GET /products/1/edit
  def edit
  end

  # POST /products
  # POST /products.json
  def create
    @product = Product.new(product_params)

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

  # PATCH/PUT /products/1
  # PATCH/PUT /products/1.json
  def update
    respond_to do |format|
      if @product.update(product_params)
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
        format.json { render :show, status: :ok, location: @product }
      else
        format.html { render :edit }
        format.json { render json: @product.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /products/1
  # DELETE /products/1.json
  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to products_url, notice: 'Product was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_product
      @product = Product.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def product_params
      params.require(:product).permit(:nombre, :descripcionBreve, :descripcionDetallada, :precioNormal, :precioOferta, :inicioOferta, :terminoOferta, :calificacion, :entregaResultados, :duracionServicio, :URLvideo, :categoria, :subcategoria, :lugarEntrega, :diasAnticipacion, :menorAnticipacion, :diasAtrasoAnticipacion, :aumentoAtrasoAnticipacion, :numeroPagos, :diasAnticipoLiquidacion, :imagenPrincipal, :visible, :manejarInventario, :stock, :permitePagosLibres, imagenes_producto_attributes: [:imagen, :_destroy])
    end
end

show.erb

<p id="notice"><%= notice %></p>

<p>
  <strong>Nombre:</strong>
  <%= @product.nombre %>
</p>
<h2>Imagen principal</h2>
<%= image_tag @product.imagenPrincipal %>
<h2>Imagenes secundarias</h2>
<% @product.imagenes_productos.each do |imagen| %>
    <%= image_tag imagen.imagen %>
<% end %>
<p>
  <strong>Descripcionbreve:</strong>
  <%= @product.descripcionBreve %>
</p>

<p>
  <strong>Descripciondetallada:</strong>
  <%= @product.descripcionDetallada %>
</p>

<p>
  <strong>Precionormal:</strong>
  <%= @product.precioNormal %>
</p>

<p>
  <strong>Preciooferta:</strong>
  <%= @product.precioOferta %>
</p>

<p>
  <strong>Iniciooferta:</strong>
  <%= @product.inicioOferta %>
</p>

<p>
  <strong>Terminooferta:</strong>
  <%= @product.terminoOferta %>
</p>

<p>
  <strong>Calificacion:</strong>
  <%= @product.calificacion %>
</p>

<p>
  <strong>Entregaresultados:</strong>
  <%= @product.entregaResultados %>
</p>

<p>
  <strong>Duracionservicio:</strong>
  <%= @product.duracionServicio %>
</p>

<p>
  <strong>Urlvideo:</strong>
  <%= @product.URLvideo %>
</p>

<p>
  <strong>Categoria:</strong>
  <%= @product.categoria %>
</p>

<p>
  <strong>Subcategoria:</strong>
  <%= @product.subcategoria %>
</p>

<p>
  <strong>Duracionservicio:</strong>
  <%= @product.duracionServicio %>
</p>

<p>
  <strong>Lugarentrega:</strong>
  <%= @product.lugarEntrega %>
</p>

<p>
  <strong>Diasanticipacion:</strong>
  <%= @product.diasAnticipacion %>
</p>

<p>
  <strong>Menoranticipacion:</strong>
  <%= @product.menorAnticipacion %>
</p>

<p>
  <strong>Diasatrasoanticipacion:</strong>
  <%= @product.diasAtrasoAnticipacion %>
</p>

<p>
  <strong>Aumentoatrasoanticipacion:</strong>
  <%= @product.aumentoAtrasoAnticipacion %>
</p>

<p>
  <strong>Numeropagos:</strong>
  <%= @product.numeroPagos %>
</p>

<p>
  <strong>Diasanticipoliquidacion:</strong>
  <%= @product.diasAnticipoLiquidacion %>
</p>

<%= link_to 'Edit', edit_product_path(@product) %> |
<%= link_to 'Back', products_path %>

非常感谢您

您需要在 imagenes_productos table 上添加一个外键 product_id,以便 rails 知道这种关系。这就是错误的原因。 此外,对于 image_tag,您将必须以这种格式 image_tag(source, options={}) 指定图片的来源,因此您可能想要按照 image_tag("#{imagen.name}" + ".png") 或任何您的格式做更多的事情图片是。