Ruby on rails - paperclip not saving to database

2020-04-06 00:42发布

问题:

I'm trying to make a create product page in rails. This includes adding multiple images. I have one model for products one for photos and for users. I'm using the paperclip gem for photo upload. But I have 2 problems.

  1. My file input is not allowing me to select multiple images
  2. When I view a product no pictures show because pictures are not being saved to database

P.S. I use HAML and I dont have a photo controller.

Products controller

class ProductsController < ApplicationController
    before_filter :current_user, only: [:create, :destory]
    before_filter :correct_user, only: :destory

  def new 
@product = Product.new
    @photo = Photo.new
    5.times { @product.photos.build }
  end

  def create

  @photo = current_user.photos.build(params[:photo])

  @product = current_user.products.build(params[:product])
    if @product.save
        render "show", :notice => "Sale created!"
    else
        render "new", :notice => "Somehting went wrong!"
    end
end

def show
@product = Product.find(params[:id]) 
end

create product page

= form_for @product, :html => { :multipart => true } do |f|
  - if @product.errors.any?
    .error_messages
      %h2 Form is invalid
      %ul
        - for message in @product.errors.full_messages
          %li
            = message
  %p
    = f.label :name
    = f.text_field :name
  %p
    = fields_for :photos do |f_i|
      =f_i.file_field :image 

  %p.button
    = f.submit

product model

class Product < ActiveRecord::Base
  attr_accessible :description, :name, :price, :condition, :ship_method, :ship_price, :quantity, :photo
  has_many :photos, dependent: :destroy
  accepts_nested_attributes_for :photos
  belongs_to :user

photo model

class Photo < ActiveRecord::Base
  attr_accessible :product_id

  belongs_to :product
  has_attached_file :image,
    :styles => {
      :thumb=> "100x100#",
      :small  => "300x300>",
      :large => "600x600>"
        }
end

User Model

class User < ActiveRecord::Base
  attr_accessible :email, :password, :password_confirmation, :name

  attr_accessor :password
  has_many :products, dependent: :destroy
  has_many :photos,:through=>:products

show product page

  %b seller
  = @product.user.name
  %br 
  - @product.photos.each do |photo|
    = image_tag photo.image.url

回答1:

Are you using Resque for background job,if yes then u need to start it using rake resque:work QUEUE='*'.in rails usually Resque is used to handle background jobs which involves mailer and picture upload.OR an example below for product.html.erb having partial for photos upload for that product with paperclip configures with Amazon S3.

product.html.erb

<%= render :partial => 'photos' %>

_photos.html.erb for atleast one image mandatory

       <% if @product.photos[0].nil? %>
                <a href="javascript:void(0);" class="add-photos" >
                <img src="/assets/default/product-add-photos.png" alt="Add product photos"/>              
                 </a>   
        <% end %>
 <img src="<%= (@product.product_photos[0].nil? ? "" : @product.photos[0].image.url(:small)) %>" id="photos_1" class="product-photos-src <%=@product.photos[0].nil? ? 'dontdisplay' : ''%> "/>


回答2:

your User model not attached to photos so photos only are belongs to Product model so you need to change your User model to be

 class User < ActiveRecord::Base
  has_many :products
  has_many :photos,:through=>:products


  end

then you can fetch User photos through

 @photos =current_user.photos 

or you can build a photo easily

@photo = current_user.photos.build(params[:photo])

also in your views you need to do instead of = f.file_field :photo, multiple: 'multiple'

use

= fields_for :photos do |f_i|
    =f_i.file_field :image

try it .

these is the simple way for has many through association

   class Document < ActiveRecord::Base
  has_many :sections
  has_many :paragraphs, :through => :sections
  end

 class Section < ActiveRecord::Base
 belongs_to :document
  has_many :paragraphs
end

class Paragraph < ActiveRecord::Base
 belongs_to :section
 end

you can check these guide for more info

http://guides.rubyonrails.org/association_basics.html also you need to put

 accepts_nested_attributes_for :photos

inside your Product model

for a complete tutorial about nested forms you can watch these screen cast

http://railscasts.com/episodes/196-nested-model-form-revised

its not free

you can watch these free screen cast if your not subscribed to railscasts.com

http://railscasts.com/episodes/196-nested-model-form-part-1

http://railscasts.com/episodes/197-nested-model-form-part-2



回答3:

Give this a try:

new product page

= form_for @product, :html => {:multipart => true} do |f|
  %p
    = f.label :description
    = f.text_field :description

  = f.fields_for :photo do |fp|
    = fp.file_field :image
    = fp.check_box :_destroy
    = fp.label :_destroy, "Remove Image" 

  %p.button
    = f.submit

products controller

def new
  @product = Product.new
  @product.photos.build
end

def create  
  @product = current_user.products.create(params[:product])
  # or
  # @product = current_user.products.build(params[:product])
  # @product.save
end

product model

class Product < ActiveRecord::Base
  attr_accessible :description, :name, :photo
  accepts_nested_attributes_for :photo, :reject_if => lambda { |p| p[:image].nil? }, :allow_destroy => true

  belongs_to :user
  has_many :photos, dependent: :destroy

  validates :user_id,      presence: true
  validates :photo,        presence: true
end

photo model

class Photo < ActiveRecord::Base
  attr_accessible :image
  belongs_to :product
    validates_attachment :image, presence: true,
         content_type: { content_type: ['image/jpeg', 'image/jpg', 'image/png', 'image/gif'] },
         size: { less_than: 5.megabytes }
    has_attached_file :image, styles: { medium: "320x240>"}

end


回答4:

  1. If you are using nested form, you dont need to create each object separately. Creating product will create the nested photo.
  2. build method only creates an object. It doesnt save the object to db. You should call object.save or use create method instead of build in your create action


回答5:

I think the real issue here is that you want to attach multiple photo's on one model through paperclip. Paperclip can only attach 1 file per model, so I suggest you do this:

1. create model Photo with paperclip migrations + has_attached_file
2. Product has_many :photos
3. (optional) make a function to return all image urls, otherwise just call the method in the view

   class Product 
     def get_pics
        photos.collect{|p| p.image.url}
     end
   end

Also a good thing, you can include meta data like alt texts and stuff in the photo model now!

<% @product.photos.each do |photo| %>
  <%= image_tag photo.image.url, :alt => photo.alt_text %>
<% end %>


回答6:

I also encountered same issue. I asked on stackoverflow and finally solved myself and rails cast help.

First thing to change is: You have to follow this to implement nested attributes in model side and controller end:

http://api.rubyonrails.org/classes/ActiveRecord/NestedAttributes/ClassMethods.html

Then follow the link below, check my answer to the question it includes rails cast links that you should follow for nested forms:

You will see rails cast 2nd link dynamically separate your each filed field as on its own it fails to separate each set of fields. But there is also lack of identity uniqueness algo accuracy in rails-cast. So I enhanced to make sure the uniqueness of certain set of fields to other.

jquery render partial just one time, for second time it not render again just shows previous one