天天看點

使用Rails和回形針上傳

這是“使用Rails上傳”系列中的最後一篇文章。 在過去的幾個月中,我們已經讨論了神殿,蜻蜓和載波波的寶石。 今天的客人是Thoughtbot的Paperclip ,該公司管理着諸如FactoryGirl和Bourbon之類的寶石。

Paperclip可能是Rails最受歡迎的附件管了解決方案(下載下傳量超過1300萬),并且有一個很好的理由:它具有許多功能,強大的社群和詳盡的文檔。 是以,希望您渴望了解有關此寶石的更多資訊!

在本文中,您将學習如何:

  • 準備回形針安裝
  • 将Paperclip內建到Rails應用程式中
  • 添加附件驗證
  • 生成縮略圖并處理圖像
  • 混淆URL
  • 在Amazon S3上存儲附件
  • 通過引入授權邏輯來保護雲中的檔案

GitHub上提供了本文的源代碼。

準備工作

在深入研究代碼之前,讓我們首先讨論一些要成功使用Paperclip時需要了解的警告 :

  • Paperclip的最新版本支援Rails 4.2+和Ruby 2.1+。 該寶石也可以在沒有Rails的情況下使用。
  • ImageMagick必須安裝在您的PC上(所有主要平台都可用),并且Paperclip應該能夠通路它。
  • file

    指令應該可以從指令行使用。 對于Windows,可通過開發工具包獲得,是以,如果尚未安裝DevKit,請按照以下說明進行操作 。

準備就緒後,繼續建立沒有預設測試套件的新Rails應用程式(我将使用Rails 5.0.2):

rails new UploadingWithPaperclip -T
           

內建回形針

放入回形針寶石:

寶石檔案

gem "paperclip", "~> 5.1"
           

安裝它:

bundle install
           

假設我們正在建立一個展示書單的書架應用程式。 每本書都有标題,描述,作者姓名和封面圖像。 首先,請生成并應用以下遷移:

rails g model Book title:string description:text image:attachment author:string
rails db:migrate
           

請注意Paperclip為我們提供的

attachment

類型。 在幕後,它将為我們建立四個字段:

  • image_file_name

  • image_file_size

  • image_content_type

  • image_updated_at

與Shrine和Carrierwave寶石相反,Paperclip沒有單獨的配置檔案。 所有設定都是使用

has_attached_file

方法在模型内部定義的,是以請立即添加:

型号/book.rb

has_attached_file :image
           

在繼續學習主要部分之前,我們還建立一個控制器以及一些視圖和路線。

建立控制器,視圖和路徑

我們的控制器将是非常基本的:

books_controller.rb

class BooksController < ApplicationController
  before_action :set_book, only: [:show, :download]

  def index
    @books = Book.order('created_at DESC')
  end

  def new
    @book = Book.new
  end

  def show
  end

  def create
    @book = Book.new(book_params)
    if @book.save
      redirect_to books_path
    else
      render :new
    end
  end

  private

  def book_params
    params.require(:book).permit(:title, :description, :image, :author)
  end

  def set_book
    @book = Book.find(params[:id])
  end
end
           

這是索引視圖和局部視圖:

views / books / index.html.erb

<h1>Bookshelf</h1>

<%= link_to 'Add book', new_book_path %>
<ul>
  <%= render @books %>
</ul>
           

views / books / _book.html.erb

<li>
  <strong><%= link_to book.title, book_path(book) %></strong> by <%= book.author %>
</li>
           

現在的路線:

config / routes.rb

Rails.application.routes.draw do
  resources :books
  root to: 'books#index'
end
           

真好! 現在,讓我們繼續到主要部分,并編寫新動作和表單的代碼。

上載檔案

總而言之,使用Paperclip進行上傳很容易。 您隻需要允許相應的屬性(在我們的例子中是

image

屬性,并且我們已經允許了它)并在您的表單中顯示檔案字段。 讓我們現在就開始做吧:

views / books / new.html.erb

<h1>Add book</h1>

<%= render 'form', book: @book %>
           

views / books / _form.html.erb

<%= form_for book do |f| %>
  <div>
    <%= f.label :title %>
    <%= f.text_field :title %>
  </div>

  <div>
    <%= f.label :author %>
    <%= f.text_field :author %>
  </div>

  <div>
    <%= f.label :description %>
    <%= f.text_area :description %>
  </div>

  <div>
    <%= f.label :image %>
    <%= f.file_field :image %>
  </div>

  <%= f.submit %>
<% end %>
           

使用此設定,您已經可以開始執行上傳了,但是最好引入一些驗證。

添加驗證

驗證在回形針可以使用舊助手等書面

validates_attachment_presence

validates_attachment_content_type

或通過采用

validates_attachment

方法一次定義多個規則。 讓我們堅持使用後一種選擇:

型号/book.rb

validates_attachment :image,
                       content_type: { content_type: /\Aimage\/.*\z/ },
                       size: { less_than: 1.megabyte }
           

如您所見,該代碼非常簡單。 我們要求檔案的圖像大小小于1兆位元組。 請注意,如果驗證失敗,将不執行任何後處理。 回形針已經為英語設定了一些錯誤消息,但是如果您想支援其他語言,請将回形針i18n gem包含在Gemfile中 。

值得一提的另一件事是,回形針要求您驗證所有附件的内容類型或檔案名,否則将引發錯誤。 如果您100%确定不需要此類驗證(這種情況很少見),請使用

do_not_validate_attachment_file_type

明确指出不應檢查的字段。

添加驗證後,我們還以表單形式顯示錯誤消息:

views / shared / _errors.html.erb

<% if object.errors.any? %>
  <h3>Some errors were found:</h3>
  <ul>
    <% object.errors.full_messages.each do |message| %>
      <li><%= message %></li>
    <% end %>
  </ul>
<% end %>
           

views / books / _form.html.erb

<%= render 'shared/errors', object: book %>
           

顯示影像

好的,現在應該以某種方式顯示上傳的圖像。 這是通過使用

image_tag

幫助器和

url

方法完成的。 建立一個顯示視圖:

views / books / show.html.erb

<h1><%= @book.title %> by <%= @book.author %></h1>

<%= image_tag(@book.image.url) if @book.image.exists? %>

<p><%= @book.description %></p>
           

僅當驅動器上确實存在圖像時,我們才顯示它 。 此外,如果您使用的是雲存儲,那麼Paperclip将執行網絡請求并檢查檔案的存在。 當然,此操作可能需要一些時間,是以您可以使用

present?

file?

方法:它們隻是確定

image_file_name

字段填充了某些内容。

URI混淆

預設情況下,所有附件都存儲在public / system檔案夾中,是以您可能希望将其從版本控制系統中排除:

.gitignore

public/system
           

但是,顯示檔案的完整URI并非總是一個好主意,并且您可能需要以某種方式對其進行混淆。 啟用混淆的最簡單方法是為

has_attached_file method

提供兩個參數:

型号/book.rb

url: "/system/:hash.:extension",
hash_secret: "longSecretString"
           

适當的值将自動插入到

url

hash_secret

是必填字段,生成它的最簡單方法是使用:

rails secret
           

處理樣式

在許多情況下,最好以預定的寬度和高度顯示圖像的縮略圖,以節省帶寬。 回形針通過使用樣式來解決此問題:每個樣式都有一個名稱和一組規則,例如尺寸,格式,品質等。

假設我們希望将原始圖像及其縮略圖轉換為JPEG格式。 縮略圖應裁剪為300x300px:

型号/book.rb

has_attached_file :image,
                    styles: {
                        thumb: ["300x300#", :jpeg],
                        original: [:jpeg]
                    }
           

#

是幾何設定,其含義是:“如果需要,請在保持寬高比的同時進行裁剪。”

我們還可以為每種樣式提供其他轉換選項。 例如,讓我們為拇指提供70%的品質,同時删除所有中繼資料,為原始圖像提供90%的品質以使其更小:

型号/book.rb

has_attached_file :image,
                    styles: {
                        thumb: ["300x300#", :jpeg],
                        original: [:jpeg]
                    },
                    convert_options: {
                        thumb: "-quality 70 -strip",
                        original: "-quality 90"
                    }
           

真好! 顯示縮略圖并提供原始圖像的連結:

views / books / show.html.erb

<%= link_to(image_tag(@book.image.url(:thumb)), @book.image.url, target: '_blank') if @book.image.exists? %>
           

請注意,例如,與Carrierwave不同,Paperclip不允許您編寫

@book.image.thumb.url

如果由于某種原因希望手動更新上傳的圖像,則可以使用以下指令僅重新整理縮略圖,添加缺少的樣式或重新整理所有圖像:

  • rake paperclip:refresh:thumbnails CLASS=Book

  • rake paperclip:refresh:missing_styles CLASS=Book

  • rake paperclip:refresh CLASS=Book

在雲中存儲檔案

像所有類似的解決方案一樣,Paperclip 允許您将檔案上傳到雲中。 開箱即用,它支援S3和Fog擴充卡,但是Azure和Dropbox都有第三方gem。 在本部分中,我将向您展示如何将Paperclip與Amazon S3內建。 首先,放入aws-sdk gem:

gem 'aws-sdk'
           

安裝它:

bundle install
           

接下來,為

has_attached_file

方法提供一組新的選項:

型号/book.rb

has_attached_file :image,
                    styles: {
                        thumb: ["300x300#", :jpeg],
                        original: [:jpeg]
                    },
                    convert_options: {
                        thumb: "-quality 70 -strip",
                        original: "-quality 90"
                    },
                    storage: :s3,
                    s3_credentials: {
                        access_key_id: ENV["S3_KEY"],
                        secret_access_key: ENV["S3_SECRET"],
                        bucket: ENV["S3_BUCKET"]
                    },
                    s3_region: ENV["S3_REGION"]
           

在這裡,我堅持使用dotenv-rails gem來設定環境變量。 您可以直接在模型内部提供所有值,但不要使其公開可用。

有趣的是

s3_credentials

還接受包含密鑰和存儲桶名稱的YAML檔案的路徑。 此外,您可以為不同的環境設定不同的值,如下所示:

development:
  access_key_id: key1
  secret_access_key: secret1
production:
  access_key_id: key2
  secret_access_key: secret2
           

而已! 現在,您上傳的所有檔案都将位于S3存儲桶中。

保護雲中的檔案

假設您不希望所有人都可以使用自己上傳的檔案。 預設情況下,所有上傳到雲中的檔案都标記為公開,這意味着任何人都可以通過直接連結打開檔案。 如果您希望引入一些授權邏輯并檢查誰可以檢視該檔案,則将

s3_permissions

選項設定為

:private

如下所示:

has_attached_file :image,
                    styles: {
                        thumb: ["300x300#", :jpeg],
                        original: [:jpeg]
                    },
                    convert_options: {
                        thumb: "-quality 70 -strip",
                        original: "-quality 90"
                    },
                    storage: :s3,
                    s3_credentials: {
                        access_key_id: ENV["S3_KEY"],
                        secret_access_key: ENV["S3_SECRET"],
                        bucket: ENV["S3_BUCKET"]
                    },
                    s3_region: ENV["S3_REGION"],
                    s3_permissions: :private
           

但是,現在,除了您之外,沒有人可以看到這些檔案。 是以,讓我們為

BooksController

建立一個新的

download

操作:

books_controller.rb

def download
    redirect_to @book.image.expiring_url
  end
           

此操作将僅通過過期連結将使用者重定向到該圖像。 使用這種方法,您現在可以使用CanCanCan或Pundit之類的gem引入任何授權邏輯。

不要忘記設定會員路線:

config / routes.rb

resources :books do
    member do
      get 'download'
    end
  end
           

該幫助程式應該這樣使用:

link_to('View image', download_book_path(@book), target: '_blank')
           

結論

我們到了本文的結尾! 今天,我們已經看到了用于Rails的附件管了解決方案Paperclip,并讨論了其主要概念。 該gem還有更多内容,是以請務必檢視其文檔 。

此外,我建議通路Paperclip的Wiki頁面,因為它提供了“操作方法”清單的清單以及指向支援Azure和Cloudinary的第三方gem的大量連結,并允許您輕松地縮小上傳的檔案。

感謝您與我在一起,很快再見!

翻譯自: https://code.tutsplus.com/articles/uploading-with-rails-and-paperclip--cms-28412

繼續閱讀