这是“使用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