PaperClip未找到处理程序错误

时间:2015-12-21 11:53:02

标签: ruby-on-rails ruby-on-rails-3 ruby-on-rails-4

您好我有2个模型ProductsProductImageProduct 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

1 个答案:

答案 0 :(得分:1)

为什么要循环使用参数并执行create方法?

-

您应该能够通过imagesaccepts_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,则可以根据需要添加额外的尺寸。