almost 4 years ago

系統:

Mac OS X Yosemite 10.10.1
Ruby 2.2.0
Rails 4.2.0
Imagemagick ( 可執行 $ brew install imagemagick 安裝,用於上傳圖檔縮圖 )

相關連結

Paperclip ( https://github.com/thoughtbot/paperclip )
Figaro ( https://github.com/laserlemon/figaro )
aws-sdk ( https://github.com/aws/aws-sdk-ruby )
Amazon Web Services ( https://aws.amazon.com/ )

前言

之前有介紹過 paperclip 來上傳任意格式的檔案至本機的空間(使用 paperclip 實作任意格式檔案上傳),現在再來修改一下設定,就可以實作上傳至 Amazon Web Services 的 S3 空間。

設定步驟如下

1. Gemfile 設定

添加必要的 gem 套件至 Gemfile 檔中

# Use Figaro manage auth_key & auth_secret
gem 'figaro'

# Use paperclip to upload files with aws s3
gem 'paperclip', '~> 4.2'
gem 'aws-sdk'

之後,執行以下指令安裝以上的 gems

$ bundle install

2. 使用鷹架(scaffold)新增 migration, controller, model, views

要做為上傳的欄位屬性為 attachment, 它會在資料表自動產生 4 個欄位 upload_file_nameupload_content_typeupload_file_sizeupload_updated_at

$ rails g scaffold download title:string upload:attachment
$ rake db:migrate

3. 設定 Paparclip with S3

新增檔案 config/initializers/paperclip.rb,可執行以下指令新增

$ touch config/initializers/paperclip.rb

新增內容如下

config/initializers/paperclip.rb
Paperclip::Attachment.default_options[:url] = ':s3_domain_url'
Paperclip::Attachment.default_options[:path] = '/:class/:attachment/:id_partition/:style/:hash.:extension'
Paperclip::Attachment.default_options[:hash_secret] = 'get_use_rake_secret'

新增以下內容至 config/environments/development.rbconfig/environments/production.rb

  ...
  # For paperclip
  config.paperclip_defaults = {
    :storage => :s3,
    :s3_credentials => {
      :bucket => ENV['S3_BUCKET_NAME'],
      :access_key_id => ENV['AWS_ACCESS_KEY_ID'],
      :secret_access_key => ENV['AWS_SECRET_ACCESS_KEY']
    }
  }

4. 使用 figaro 管理環境參數

$ figaro install

此時會產生 config/application.yml.gitignore 會多以下內容

...
# Ignore application configuration
/config/application.yml

新增以下內容至 config/application.yml,至於如何取得 AWS_ACCESS_KEY_ID 和 AWS_SECRET_ACCESS_KEY,請參考 此篇教學

config/application.yml
S3_BUCKET_NAME: 'your_S3_bucket_name'
AWS_ACCESS_KEY_ID: 'your_aws_access_key_id'
AWS_SECRET_ACCESS_KEY: 'your_aws_secret_access_key'

為了避免金鑰的環境參數遭人盜用,所以,我們是不上傳 /config/application.yml 至 git 空間,但是為了記錄我們有使用哪些環境參數,我們可以新增檔案 config/application.yml.example,方便的新增指令及內容如下

$ cp config/application.yml{,.example}
config/application.yml.example
S3_BUCKET_NAME: ''
AWS_ACCESS_KEY_ID: ''
AWS_SECRET_ACCESS_KEY: ''

5. Model 設定

只能上傳圖檔的設定
app/models/download.rb
class Download < ActiveRecord::Base
  has_attached_file :upload, styles: {
    medium: '300x300>',
    thumb: '100x100>'
  }
  validates_attachment :upload, content_type: { content_type: /\Aimage\/.*\Z/ },
                                size: { in: 0..1.megabytes }
  validates :title, presence: true
  validates :upload, presence: true
end
可以上傳任意格式檔案的設定,並且針對圖檔會進行縮圖
app/models/download.rb
class Download < ActiveRecord::Base
  has_attached_file :upload, styles: {
    medium: '300x300>',
    thumb: '100x100>'
  }
  validates_attachment :upload, size: { in: 0..5.megabytes },
                                file_type_ignorance: true
  validates :title, presence: true
  validates :upload, presence: true

  before_post_process :resize_images

  def image?
    upload_content_type =~ /\Aimage\/.*\Z/
  end

  private

  def resize_images
    return false unless image?
  end
end

6. Controller 設定

筆者是用 rails 4.2.0 鷹架(scaffold),基本上 controller 設定不用動到,以下為鷹架(scaffold)自動產生的內容。

class DownloadsController < ApplicationController
  before_action :set_download, only: [:show, :edit, :update, :destroy]

  # GET /downloads
  # GET /downloads.json
  def index
    @downloads = Download.all
  end

  # GET /downloads/1
  # GET /downloads/1.json
  def show
  end

  # GET /downloads/new
  def new
    @download = Download.new
  end

  # GET /downloads/1/edit
  def edit
  end

  # POST /downloads
  # POST /downloads.json
  def create
    @download = Download.new(download_params)

    respond_to do |format|
      if @download.save
        format.html { redirect_to @download, notice: 'Download was successfully created.' }
        format.json { render :show, status: :created, location: @download }
      else
        format.html { render :new }
        format.json { render json: @download.errors, status: :unprocessable_entity }
      end
    end
  end

  # PATCH/PUT /downloads/1
  # PATCH/PUT /downloads/1.json
  def update
    respond_to do |format|
      if @download.update(download_params)
        format.html { redirect_to @download, notice: 'Download was successfully updated.' }
        format.json { render :show, status: :ok, location: @download }
      else
        format.html { render :edit }
        format.json { render json: @download.errors, status: :unprocessable_entity }
      end
    end
  end

  # DELETE /downloads/1
  # DELETE /downloads/1.json
  def destroy
    @download.destroy
    respond_to do |format|
      format.html { redirect_to downloads_url, notice: 'Download was successfully destroyed.' }
      format.json { head :no_content }
    end
  end

  private
    # Use callbacks to share common setup or constraints between actions.
    def set_download
      @download = Download.find(params[:id])
    end

    # Never trust parameters from the scary internet, only allow the white list through.
    def download_params
      params.require(:download).permit(:title, :upload)
    end
end

7. View 設定

最重要的就是 form 要設定好!!

app/views/downloads/_form.html.erb
<%= form_for(@download, html: { multipart: true }) do |f| %>
  ...
  <div class="field">
    <%= f.label :upload %><br>
    <%= f.file_field :upload %>
  </div>
  ...
<% end %>

接下來就可以啟動伺服器,並打開網頁 http://localhost:3000/downloads 測試是否可以正常上傳任意格式檔案至 AWS 的 S3 空間摟!!

8. 上傳後檔案路徑

上傳後的檔案路徑可以透過以下方式取得

# 原始檔
<%= @download.upload %>
<%= @download.upload.url %>
# 圖檔縮圖
<%= @download.upload.url(:medium) %>
<%= @download.upload.url(:thumb) %>
← 打造專屬 gem - part 2 - 新增自製 Helper、Assets 檔案 AWS EC2 - part 1 - 使用 chef 配置基本系統環境 →
 
comments powered by Disqus