jamesfwz
6/17/2014 - 10:32 AM

Paperclip.md

Setup

  • Install the gem gem "paperclip", "~> 3.0"
# Create Database
class AddPhotoToDeals < ActiveRecord::Migration
  def self.up
    add_attachment :deals, :photo
  end

  def self.down
    remove_attachment :deals, :photo
  end
end

# Add to model
has_attached_file :photo, styles: {:medium => "300x300>", :thumb => "100x100>"},
                          default_url: "/images/missing.png"
                          
# Remember to create an image at /images/missing.png

# Validation
validates_attachment :photo,  presence: true,
                          content_type: {content_type: "image/jpg"},
                                  size: {in: 0..1.megabytes}

# Individual validation
validates_attachment_presence :photo

validates_attachment_content_type :photo,
                            content_type: /^image\/(jpg|jpeg|pjpeg|png|x-png|gif)$/,
                                 message: 'file type is not allowed (only jpeg/png/gif images)'

validates_attachment_size :photo,
                          in: 0..1.megabytes,
                          message: "file size cannot be larger than 1 MB"                          

S3 Setup for Paperclip

# Add the following to your config/environments/production.rb and development.rb  
config.paperclip_defaults = {
    storage: :s3,
    s3_protocol: 'http',
    path: ":rails_root/public/system/production/:class/:attachment/:id_partition/:style/:filename",
    s3_credentials: {
        bucket: ENV['AWS_BUCKET'],
        access_key_id: ENV['AWS_ACCESS_KEY_ID'],
        secret_access_key: ENV['AWS_SECRET_ACCESS_KEY']
    }
}

# Tip: Config needed to be set in production via command-line for Heroku
# heroku config:set AWS_BUCKET=stapi-us
# heroku config:set AWS_ACCESS_KEY_ID=XXXX
# heroku config:set AWS_SECRET_ACCESS_KEY=XXXX

# Alternative setup if you have errors with S3 endpoints
config.paperclip_defaults = {
    storage: :s3,
    s3_protocol: 'http',
    path: "/production/:class/:attachment/:id_partition/:style/:filename",
    s3_credentials: {
      bucket: 'ABC',
      access_key_id: '123123',
      secret_access_key: '123123',
    },
    url: ":s3_domain_url"
}

Simple_form

= simple_form_for @product do |f|
  = f.input :title
  = f.input :photo

Accessing Image in view

image_tag @product.photo.url
image_tag @product.photo.url(:thumb)
image_tag @product.photo.url(:medium)

Testing

Capabara Testing

describe "Create A Product" do
  let(:product) { attributes_for(:product) }

  it "should create a product" do
    # Fill up create product form
    fill_in 'Title', with: product[:title]
    fill_in 'Description', with: product[:description]
    attach_file "Photo", Rails.root.join('spec', 'fixtures', 'sample_photo.jpg') # Put your sample_photo.jpg at /spec/fixtures/sample_photo.jpg
    click_button 'Create Product'
    expect(page).to have_css "img.product_photo"
  end
end

Controller Testing

describe ProductsController do
  # fixture_file_upload will search in /spec/fixture by default
  let (:params) { attributes_for(:product).merge(photo: fixture_file_upload('sample_photo.jpg')) }
  
  describe "#create" do
    it "uploads the photo for the product" do
        post :create, product: params
        assigns(:product).photo.should_not be_nil
    end
  end
end

FactoryGirl Creation

  • Give a model Image with has_attached_file: :photo
FactoryGirl.define do
  factory :image do
    photo   File.new(Rails.root + 'spec/fixtures/sample.jpg')
    caption 'A nice caption'
  end
end

# The above method is not good as it will generate real files in the app
# Just directly create fake data in the factory
FactoryGirl.define do
  factory :image do
    photo_file_name '123.jpg'
    photo_content_type 'image/jpg'
    photo_file_size 1024
    photo_updated_at { DateTime.now }
    caption 'A nice caption'
  end
end
    



Image styling guide