Rails Activerecord,嵌套验证

时间:2016-05-20 13:33:10

标签: ruby-on-rails ruby activerecord carrierwave cocoon-gem

我已经担心这个错误太多天了,我不确定我错过了什么。

我有一个名为'产品'和它的孩子&product;附属品'。 子模型中的验证在创建时成功通过/ product_attachments禁用空白图像字段#new

但是,当使用其父表单/产品#new(下面的文件)时,我希望它在没有图像的情况下验证成功失败。但是,Activerecord忽略了错误,如果验证通过然后抱怨我的product_attachments为空,我的控制器会尝试保存。

我目前的理解是使用' validates_associated'将验证子模型作为父进程的一部分,但这并没有奏效。 我们离开表单而控制器尝试处理由于没有附件而失败的创建方法,而不是传递快乐失败的验证中间格式以允许用户采取操作。 因为我应该总是有一个附件一直试图修复这个验证无济于事。

任何帮助表示赞赏,我之前已提供类似的代码示例,以供您反馈。 我对rails非常陌生,所以我希望我误用关键语法或上下文。

还好奇是什么原因以及最好的解决方法,因为我仍在开发良好的调试实践。

product.rb

class Product < ActiveRecord::Base

  has_many :product_attachments
  validates_presence_of :title, :message =>  "You must provide a name for this product."
  accepts_nested_attributes_for :product_attachments, allow_destroy: true#, 
  validates_associated :product_attachments
end

product_attachment.rb (用于处理此处使用的上传的载波,似乎工作正常)

class ProductAttachment < ActiveRecord::Base
  belongs_to :product 
  mount_uploader :image, ImageUploader
  validates_presence_of :image, :message =>  "You must upload an image to go with this item."
end

products_controller.rb

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

  def index
    @products = Product.all
  end

  def show
    @product_attachments = @product.product_attachments.all
  end

  def new
    @product = Product.new
    @product_attachment = @product.product_attachments.build
  end

  def edit
  end

  def create
    @product = Product.new(product_params)
    respond_to do |format|
      if @product.save
        params[:product_attachments]['image'].each do |a|
          @product_attachment = @product.product_attachments.create!(:image => a)
        end
        format.html { redirect_to @product, notice: 'Product was successfully created.' }
      else #- when would this fire?
        format.html { render :new }
      end
    end
  end

  def update
    respond_to do |format|
      if @product.update(product_params)
          params[:product_attachments]['image'].each do |a|
            @product_attachment = @product.product_attachments.create!(:image => a, :post_id => @post.id)
          end
        format.html { redirect_to @product, notice: 'Product was successfully updated.' }
      else #- when would this fire?
        format.html { render action: 'new' }
      end
    end
  end

  def destroy
    @product.destroy
    respond_to do |format|
      format.html { redirect_to @product, notice: 'Product was successfully destroyed.' }
    end
  end

  private
    def set_product
      @product = Product.find(params[:id])
    end
    # we pass the _destroy so the above model has the access to delete
    def product_params
      params.require(:product).permit(:id, :title, :price, :barcode, :description, product_attachment_attributes: [:id, :product_id, :image, :filename, :image_cache, :_destroy])
    end

end

product_attachments_controller.rb

class ProductAttachmentsController < ApplicationController
  before_action :set_product_attachment, only: [:show, :edit, :update, :destroy]

  def index
    @product_attachments = ProductAttachment.all
  end

  def show
  end

  def new
    @product_attachment = ProductAttachment.new
  end

  def edit
  end

  def create
    @product_attachment = ProductAttachment.new(product_attachment_params)

    respond_to do |format|
      if @product_attachment.save
        @product_attachment.image = params[:image]
        format.html { redirect_to @product_attachment, notice: 'Product attachment was successfully created.' }
      else
        format.html { render :new }
      end
    end
  end

  def update
    respond_to do |format|
      if @product_attachment.update(product_attachment_params)
        @product_attachment.image = params[:image]
        format.html { redirect_to @product_attachment.product, notice: 'Product attachment was successfully updated.' }
      else
        format.html { render :edit }
      end
    end
  end

  def destroy
    @product_attachment.destroy
    respond_to do |format|
      format.html { redirect_to product_attachments_url, notice: 'Product attachment was successfully destroyed.' }
    end
  end

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

    def product_attachment_params
      params.require(:product_attachment).permit(:id, :product_id, :image, :image_cache)
    end
end

_form.html.slim (在这里使用simple_form + slim + cocoon ......)

= simple_form_for @product do |f|

  - if @product.errors.any?
    #error_explanation
      h2
        = pluralize(@product.errors.count, "error")
        |  prohibited this product from being saved:
      ul 
        - @product.errors.each do |attribute, message|
          - if message.is_a?(String)
            li= message

  = f.input :title
  = f.input :price, required: true
  = f.input :barcode
  = f.input :description

  h3 attach product images
  #product_attachment
    = f.simple_fields_for :product_attachments do |product_attachment|
      = render 'product_attachment_fields', f: product_attachment
    .links
      = link_to_add_association 'add product attachment', f, :product_attachments
  = f.submit

_product_attachment_fields.html.slim 注意我需要以这种方式命名我的文件字段,以便我的控制器正确使用文件,但不确定为什么还是。

.nested-fields
  = f.file_field :image , :multiple => true , name: "product_attachments[image][]"
  = link_to_remove_association "remove", f

如果我能提供其他任何信息,请告诉我。

感谢您抽出时间阅读/回复。

编辑1:我目前的调试方法我在写这篇文章的过程中通过浏览器删除代码块和测试功能。我已经读过了我应该对rails console更熟悉,但还没有到达那里。

EDIT2:

undefined method `[]' for nil:NilClass

        params[:product_attachments]['image'].each do |a|


app/controllers/products_controller.rb:47:in `block in create'
app/controllers/products_controller.rb:44:in `create'

Request

Parameters:

{"utf8"=>"✓",
 "authenticity_token"=>"{mytoken}",
 "product"=>{"title"=>"pleasefailwell",
 "commit"=>"Create Product"}

编辑3:为了清晰起见,重新编辑原始部分

1 个答案:

答案 0 :(得分:1)

看到你最新的编辑,我发现这种情况正在发生,这意味着product_attachments是零。哪个是正确的,参数应该是product_attachments_attributes

这导致了product_params方法中的另一个问题。

您有product_attachment_attributes,基本格式“字段”应该是复数形式:product_attachments_attributes

简而言之:

从控制器中删除产品附件循环。修复强params方法,它应该在那之后工作。

修改

同时从name中删除file_field属性,但这无效。