您好我有2个模型Products
和ProductImage
。 Product has_many ProductImages
。我正在使用paperclip gem。
当我提交Product Form
时,我收到此错误。
No handler found for ["0", {"product_image"=>#<ActionDispatch::Http::UploadedFile:0x007f8cb78b29c8 @tempfile=#<Tempfile:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151221-46388-dqxfk7.jpg>, @original_filename="780069_black_l.jpg", @content_type="image/jpeg", @headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n">}]
def create_product_images
params["product"]["product_images_attributes"].each do |image|
ProductImage.create(product_image: image, product_id: @form.product.id)
end
end
任何人都知道如何解决这个问题?我试图创建一个ProductImage。所以,当我去product.product_images时,我有一个包含该产品所有图像的数组。
这是表格
<%= javascript_include_tag "custom" %>
<div class="container">
<div class=“row”>
<div class="col-md-6 col-md-offset-3">
<div class="panel panel-primary">
<div class="panel-body">
<%= simple_form_for @product do |f| %>
<%= f.fields_for :product_images do |product_image| %>
<% if product_image.object.new_record? %>
<%= product_image.file_field(:product_image) %>
<% else %>
<%= image_tag(product_image.url(:thumb)) %>
<%= product_image.hidden_field :_destroy %>
<%= product_image.link_to_remove "X" %>
<% end %>
<% end %>
<%= f.collection_select :category_id, @categories, :id, :name, include_blank: true, prompt: "Select One Category" %>
<% @categories.each do |category| %>
<div class='sizes_container' id ='sizes_container_for_<%= category.id %>'>
<% category.sizes.each do |size| %>
<%= label_tag "product_form[sizes_by_id][#{size.id}]", size.title %>
<%= text_field_tag "product_form[sizes_by_id][#{size.id}]" %>
<% end %>
</div>
<% end %>
<%= f.input :title, label:"Title"%>
<%= f.input :price, label:"Price"%>
<%= f.input :description,label:"Description" %>
<%= f.input :size_description, label:"Size Details"%>
<%= f.input :shipping_description, label:"Shipping Details"%>
<%= f.input :tag_list,label:"Tags - Seperate tags using comma ','. 5 tags allowed per product" %>
<%= f.button :submit, "Create new product", class: "btn-lg btn-success" %>
<% end %>
</div>
</div>
</div>
</div>
</div>
这是params的样子
69: def create_product_images
70: params["product"]["product_images_attributes"].each do |image|
=> 71: binding.pry
72: ProductImage.create(product_image: image, product_id: @form.product.id)
73: end
74: end
[1] pry(#<ProductsController>)> params["product"]["product_images_attributes"]
=> {"0"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8cacd89b28
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n",
@original_filename="780069_black_l.jpg",
@tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151221-46388-d4pub9.jpg>>},
"1"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8cacd897b8
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"product[product_images_attributes][1][product_image]\"; filename=\"20090a.jpg\"\r\nContent-Type: image/jpeg\r\n",
@original_filename="20090a.
产品控制器
class ProductsController < ApplicationController
before_action :set_product, only: [:edit, :show, :update]
before_action :correct_user_edit, only: [:edit, :update, :destroy]
before_action :logged_in_user, only: [:new, :edit, :update, :destroy]
def index
@products = Product.all
end
def new
@product = Product.new
@categories = Category.preload(:sizes).order(:name)
@product.product_images.build
end
def home
@products = Product.paginate(page: params[:page])
end
def edit
end
def show
end
def update
if @product.update(product_params)
redirect_to @product
flash[:success] = 'Item was successfully updated.'
else
render "edit"
end
end
def create
@form = ProductForm.new(
product_image: product_params[:product_image],
title: product_params[:title],
price: product_params[:price],
size_description: product_params[:size_description],
shipping_description: product_params[:shipping_description],
description: product_params[:description],
tag_list: product_params[:tag_list],
category_id: product_params[:category_id],
sizes_by_id: product_params[:sizes_by_id],
user: current_user
)
if @form.save
create_product_images
redirect_to @form.product
flash[:success] = "You have created a new product"
else
flash[:danger] = "Your product didn't save"
new
render "new"
end
end
def destroy
@product.destroy
flash[:success] = "Product deleted"
redirect_to user_products_path
end
private
def create_product_images
params["product"]["product_images_attributes"].each do |index, image|
ProductImage.create(product_image: image, product_id: @form.product.id)
end
end
def set_product
@product = Product.find(params[:id])
end
def product_params
params.require(:product).permit(
:product_images_attributes,
:title,
:price,
:description,
:tag_list,
:category_id,
:size_description,
:shipping_description,
).merge(sizes_by_id: params[:product_form][:sizes_by_id]) # TODO
end
def correct_user_edit
if @product = current_user.products.find_by(id: params[:id])
else
redirect_to root_url if @product.nil?
end
end
end
product_form.rb
class ProductForm
attr_reader :quantity_by_size_id, :product
def initialize(product_image:, title:, price:, description:, tag_list:, category_id:, sizes_by_id:, user:, size_description:, shipping_description:)
@quantity_by_size_id = sizes_by_id # TODO
@product_images = product_image
@product = Product.new(
title: title,
price: price,
description: description,
tag_list: tag_list,
category_id: category_id,
size_description: size_description,
shipping_description: shipping_description,
user: user
)
build_product_sizes
end
def save
product.save
end
private
def build_product_sizes
quantity_by_size_id.map do |size_id, quantity|
if quantity.to_i.nonzero?
product.product_sizes.build(product: product, size_id: size_id, quantity: quantity)
end
end
end
end
Product.rb
class Product < ActiveRecord::Base
acts_as_taggable
belongs_to :user
belongs_to :category
has_many :product_sizes
has_many :product_images, :dependent => :destroy
validates :title, presence: true, length: { maximum: 30 }
validates :description, presence: true, length: { maximum: 2000 }
validates :category, :user, :price, presence: true
accepts_nested_attributes_for :product_images, allow_destroy: true
end
模式
create_table "product_sizes", force: :cascade do |t|
t.integer "quantity"
t.integer "product_id"
t.integer "size_id"
end
product_size.rb
class ProductSize < ActiveRecord::Base
belongs_to :product
belongs_to :size
validates :quantity, presence: true
end
PARAMS
From: /Users/jo/Documents/Safsy/Website/Safsy/Safsy/app/controllers/products_controller.rb @ line 36 ProductsController#create:
35: def create
=> 36: binding.pry
37: @form = ProductForm.new(
38: product_image: product_params[:product_image],
39: title: product_params[:title],
40: price: product_params[:price],
41: size_description: product_params[:size_description],
42: shipping_description: product_params[:shipping_description],
43: description: product_params[:description],
44: tag_list: product_params[:tag_list],
45: category_id: product_params[:category_id],
46: sizes_by_id: product_params[:sizes_by_id],
47: user: current_user
48: )
49: if @form.save
50: create_product_images
51: redirect_to @form.product
52: flash[:success] = "You have created a new product"
53: else
54: flash[:danger] = "Your product didn't save"
55: new
56: render "new"
57: end
58: end
[1] pry(#<ProductsController>)> params
=> {"utf8"=>"✓",
"authenticity_token"=>"3MZESoSUgrO2Bc3vl8/M0pTfTna9rjeXfXG23znsy3VGCEBcHMh+4ZC5rqSxGkQOmz4kl1JN9FFMH4lniDjFQg==",
"product"=>
{"product_images_attributes"=>
{"0"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8c9ceb22f8
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"product[product_images_attributes][0][product_image]\"; filename=\"780069_black_l.jpg\"\r\nContent-Type: image/jpeg\r\n",
@original_filename="780069_black_l.jpg",
@tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151222-46388-pgfg4b.jpg>>,
"_destroy"=>"false"},
"1450783221367"=>
{"product_image"=>
#<ActionDispatch::Http::UploadedFile:0x007f8c9ceb2140
@content_type="image/jpeg",
@headers="Content-Disposition: form-data; name=\"product[product_images_attributes][1450783221367][product_image]\"; filename=\"20090a.jpg\"\r\nContent-Type: image/jpeg\r\n",
@original_filename="20090a.jpg",
@tempfile=#<File:/var/folders/yx/znmx6qfj0c507bvkym6lvhxh0000gn/T/RackMultipart20151222-46388-3vamt4.jpg>>,
"_destroy"=>"false"}},
"category_id"=>"3",
"title"=>"new product",
"price"=>"352.40",
"description"=>"test",
"size_description"=>"test",
"shipping_description"=>"test",
"tag_list"=>"test"},
"product_form"=>{"sizes_by_id"=>{"1"=>"3", "2"=>"34", "3"=>""}},
"commit"=>"Create new product",
"controller"=>"products",
"action"=>"create"}
[2] pry(#<ProductsController>)> product_params
Unpermitted parameter: product_images_attributes
=> {"title"=>"new product",
"price"=>"352.40",
"description"=>"test",
"tag_list"=>"test",
"category_id"=>"3",
"size_description"=>"test",
"shipping_description"=>"test",
"sizes_by_id"=>{"1"=>"3", "2"=>"34", "3"=>""}}
[3] pry(#<ProductsController>)>
更新
在尝试了Rich Peck的回答后,我的产品图片仍然存在且product.product_images正在运行
我的product_params看起来像这样。
def product_params
params.require(:product).permit(
:title,
:price,
:description,
:tag_list,
:category_id,
:size_description,
:shipping_description,
product_images_attributes: [:product_image, :_destroy],
product_sizes_attributes: [:size_id, :quantity]
)
end
答案 0 :(得分:1)
为什么要循环使用参数并执行create
方法?
-
您应该能够通过images
将accepts_nested_attributes_for
传递给您的嵌套模型:
#app/models/product.rb
class Product < ActiveRecord::Base
has_many :product_images
accepts_nested_attributes_for :product_images, allow_destroy: true
end
#app/models/product_image.rb
class ProductImage < ActiveRecord::Base
belongs_to :product
has_attached_file :product_image
end
这应该将嵌套的图片对象从您的@product
表单传递到您的ProductImage
模型。
只要你允许正确的参数,它应该适合你:
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
def new
@product = Product.new
@product.product_images.build
end
def create
@product = Product.new product_params
@product.save
end
private
def product_params
params.require(:product).permit(:product, :params, product_images_attributes: [:product_image] %>
end
end
你的表格看起来还不错。
<强>更新强>
好的,关于将ProductSize
与图片一起保存,您可以使用accetps_nested_attributes_for
同时保存它们......
我总是主张使用它而不是试图在after_create
调用或其他任何事情中创建自己的类 - 保持流程一致是你能做的最重要的事情。
总之...
#app/models/product.rb
class Product < ActiveRecord::Base
has_many :product_images
has_many :product_sizes
accepts_nested_attributes_for :product_images, :product_sizes
end
#app/models/product_size.rb
class ProductSize < ActiveRecord::Base
belongs_to :product
end
#app/models/product_image.rb
class ProductImage < ActiveRecord::Base
belongs_to :product
has_attached_image :image
end
这将允许您使用以下控制器设置:
#app/controllers/products_controller.rb
class ProductsController < ApplicationController
def new
@product = Product.new
@product.product_images.build
@product.product_sizes.build
end
def create
@product = Product.new product_params
@product.save
end
private
def product_params
params.require(:product).permit(:x, :y, :z, product_images_attributes: [:image], product_sizes_attributes: [:a, :b, :c])
end
end
这将允许您使用与当前目前相似的设置:
#app/views/products/new.html.erb
<%= form_for @product do |f| %>
<%= f.fields_for :product_images do |p| %>
<%= p.file_field :image %>
<% end %>
<%= f.fields_for :product_sizes do |s| %>
<%= s.text_field :a %>
<% end %>
<%= f.submit %>
<% end %>
这将允许您使用所需的所有验证等,和如果您使用Cocoon
,则可以根据需要添加额外的尺寸。