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 )

前言

近期想把以前的 PHP 網站用 Ruby on Rails 重寫,其需要有一個任意格式的檔案上傳功能,之前有介紹過 paperclip 來上傳使用者頭像(Devise - part 3 - Add User Profile with avatar),雖然 paperclip 官網說明主要是針對圖像上傳功能,其實只要修改一下設定,就可以上傳任意格式的檔案。

設定步驟如下

1. Gemfile 設定

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

# Use paperclip to upload files
gem 'paperclip', '~> 4.2'

之後,執行以下指令安裝以上的 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. Model 設定

只能上傳圖檔的設定
app/models/download.rb
class Download < ActiveRecord::Base
  has_attached_file :upload, styles: { medium: '300x300>', thumb: '100x100>' },
                             url: '/system/:class/:attachment/:id_partition/:style/:hash.:extension',
                             path: ':rails_root/public/system/:class/:attachment/:id_partition/:style/:hash.:extension',
                             hash_secret: 'get_from_rake_secret'
  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>' },
                             url: '/system/:class/:attachment/:id_partition/:style/:hash.:extension',
                             path: ':rails_root/public/system/:class/:attachment/:id_partition/:style/:hash.:extension',
                             hash_secret: 'fa06822165fcfcb16a25b300f7c76671520559e1a0759bb0f5e977416e571b3b5e937af6b144e0095fad23ddf95624c6aaffce375c7a1d8bf5a443bf9d94dd90'
  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

4. 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

5. 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 測試是否可以正常上傳任意格式檔案摟!!

6. 上傳後檔案路徑

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

# 原始檔
<%= @download.upload %>
<%= @download.upload.url %>
# 圖檔縮圖
<%= @download.upload.url(:medium) %>
<%= @download.upload.url(:thumb) %>
← 使用 sorcery 實作簡單的使用者認證 實作連動選單 ( dynamic select ) →
 
comments powered by Disqus