這是“使用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應該能夠通路它。
-
指令應該可以從指令行使用。 對于Windows,可通過開發工具包獲得,是以,如果尚未安裝DevKit,請按照以下說明進行操作 。file
準備就緒後,繼續建立沒有預設測試套件的新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