我已经担心这个错误太多天了,我不确定我错过了什么。
我有一个名为'产品'和它的孩子&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:为了清晰起见,重新编辑原始部分
答案 0 :(得分:1)
看到你最新的编辑,我发现这种情况正在发生,这意味着product_attachments
是零。哪个是正确的,参数应该是product_attachments_attributes
。
这导致了product_params
方法中的另一个问题。
您有product_attachment_attributes
,基本格式“字段”应该是复数形式:product_attachments_attributes
简而言之:
从控制器中删除产品附件循环。修复强params方法,它应该在那之后工作。
修改强>
同时从name
中删除file_field
属性,但这无效。