Ruby
 Computer >> コンピューター >  >> プログラミング >> Ruby

RailsとCarrierwaveを使用したアップロード

これは、「Railsによるアップロード」シリーズの別の記事です。今日は、Railsで最も人気のあるファイルアップロードソリューションの1つであるCarrierwaveに会います。 Carrierwaveが好きなのは、使い始めが簡単で、すぐに使える機能がたくさんあり、コミュニティのメンバーが書いた「ハウツー」記事がたくさんあるので、迷子にならないからです。

>

この記事では、次の方法を学習します。

  • CarrierwaveをRailsアプリに統合する
  • 検証を追加する
  • リクエスト間でファイルを永続化する
  • ファイルを削除する
  • サムネイルを生成する
  • 離れた場所からファイルをアップロードする
  • 複数のファイルのアップロードを導入する
  • クラウドストレージのサポートを追加

この記事のソースコードはGitHubで入手できます。読んで楽しんでください!

基礎を築く

いつものように、新しいRailsアプリケーションを作成することから始めます:

rails new UploadingWithCarrierwave -T

このデモでは、Rails5.0.2を使用します。 Carrierwave1はRails4+とRuby2のみをサポートしていることに注意してください。まだRails3に乗っている場合は、Carrierwaveバージョン0.11を接続してください。

Carrierwaveの動作を確認するために、 Postのみを使用して非常にシンプルなブログアプリケーションを作成します。 モデル。次の主な属性があります:

  • タイトル string
  • 本体テキスト
  • 画像 string )—このフィールドには、投稿に添付された画像(正確にはファイル名)が含まれます

新しい移行を生成して適用します:

rails g model Post title:string body:text image:string
rails db:migrate

いくつかのルートを設定します:

config / routers.rb

resources :posts
root to: 'posts#index'

また、非常に基本的なコントローラーを作成します。

posts_controller.rb

class PostsController < ApplicationController
  before_action :set_post, only: [:show, :edit, :update]

  def index
    @posts = Post.order('created_at DESC')
  end

  def show
  end

  def new
    @post = Post.new
  end

  def create
    @post = Post.new(post_params)
    if @post.save
      redirect_to posts_path
    else
      render :new
    end
  end

  def edit
  end

  def update
    if @post.update_attributes(post_params)
      redirect_to post_path(@post)
    else
      render :edit
    end
  end

  private

  def post_params
    params.require(:post).permit(:title, :body, :image)
  end

  def set_post
    @post = Post.find(params[:id])
  end
end

それでは、インデックスを作成しましょう。 ビュー:

views / posts / index.html.erb

<h1>Posts</h1>

<%= link_to 'Add post', new_post_path %>

<%= render @posts %>

そして対応する部分:

views / posts / _post.html.erb

<h2><%= link_to post.title, post_path(post) %></h2>

<p><%= truncate(post.body, length: 150) %></p>

<p><%= link_to 'Edit', edit_post_path(post) %></p>
<hr>

ここでは、Railsの truncateを使用しています 投稿の最初の150個のシンボルのみを表示する方法。他のビューとフォームパーシャルを作成する前に、まずCarrierwaveをアプリケーションに統合しましょう。

Carrierwaveの統合

新しい宝石をGemfileにドロップします :

ジェムファイル

gem 'carrierwave', '~> 1.0'

実行:

bundle install

Carrierwaveは、その構成をアップローダー内に保存します モデルに含まれています。アップローダーを生成するには、次のコマンドを使用します。

rails generate uploader Image

さて、 app / uploadersの内部 、 image_uploader.rbという新しいファイルがあります 。いくつかの有用なコメントと例があることに注意してください。それを使用して開始することができます。このデモではActiveRecordを使用しますが、CarrierwaveはMongoid、Sequel、およびDataMapperもサポートしています。

次に、インクルードまたはマウントする必要があります このアップローダーをモデルに追加します:

models / post.rb

mount_uploader :image, ImageUploader

アップローダーにはすでに適切なデフォルト設定がありますが、少なくとも、アップロードされたファイルを保存する場所を選択する必要があります。今のところ、ファイルストレージを使用しましょう:

uploaders / image_uploader.rb

storage :file

デフォルトでは、ファイルは public / uploads内に配置されます ディレクトリなので、バージョン管理システムから除外するのが最善です:

.gitignore

public/uploads

store_dirを変更することもできます アップローダー内のメソッドを使用して、他の場所を選択します。

この時点で、ファイルのアップロードを開始するための新しいビューとフォームの一部を作成できます。

views / posts / new.html.erb

<h1>Add post</h1>

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

views / posts / _form.html.erb

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

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

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

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

PostsControllerに注意してください image はすでに許可されているため、変更する必要はありません。 属性。

最後に、編集ビューを作成します:

views / posts / edit.html.erb

<h1>Edit post</h1>

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

それでおしまい!サーバーを起動して、画像を使用して投稿を作成してみてください。問題は、この画像がどこにも表示されないことです。次のセクションに進み、表示ページを追加しましょう!

画像の表示

したがって、まだ作成していないビューは showだけです。 。今すぐ追加:

views / posts / show.html.erb

<%= link_to 'All posts', posts_path %>
<h1><%= @post.title %></h1>

<%= image_tag(@post.image.url, alt: 'Image') if @post.image? %>

<p><%= @post.body %></p>

<p><%= link_to 'Edit', edit_post_path(@post) %></p>

ご覧のとおり、添付ファイルの表示は非常に簡単です。必要なのは、 @ post.image.urlと言うことだけです。 画像のURLを取得します。ファイルへのパスを取得するには、 current_pathを使用します 方法。 Carrierwaveはimage?も提供することに注意してください 添付ファイルが存在するかどうかを確認するためのメソッド( image メソッド自体がnilを返すことはありません 、ファイルが存在しない場合でも)

これで、投稿に移動した後、画像が表示されるはずですが、大きすぎるように見える場合があります。結局のところ、サイズを制限しているわけではありません。もちろん、いくつかのCSSルールを使用して画像を縮小することもできますが、ファイルのアップロード後にサムネイルを生成する方がはるかに優れています。ただし、これにはいくつかの追加手順が必要です。

サムネイルの生成

画像を切り抜いて拡大縮小するには、別のツールが必要です。箱から出して、CarrierwaveはRMagickとMiniMagickの宝石をサポートしており、これらはImageMagickの助けを借りて画像を操作するために使用されます。 ImageMagickは、既存の画像を編集して新しい画像を生成できるオープンソースソリューションであるため、先に進む前に、画像をダウンロードしてインストールする必要があります。次に、2つの宝石のどちらかを自由に選ぶことができます。インストールがはるかに簡単で、サポートも優れているため、MiniMagickを使用します。

ジェムファイル

gem 'mini_magick'

実行:

bundle install

次に、MiniMagickをアップローダーに含めます:

uploaders / image_uploader.rb

include CarrierWave::MiniMagick

ここで、アップローダーに新しいバージョンを導入する必要があります。 バージョンの概念 (またはスタイル)は、多くのファイルアップロードライブラリで使用されます。これは単に、元の添付ファイルに基づく追加のファイルが、たとえば、異なる寸法や形式で作成されることを意味します。 thumbという新しいバージョンを紹介します :

uploaders / image_uploader.rb

version :thumb do
    process resize_to_fill: [350, 350]
end

好きなだけバージョンを作成できます。さらに、バージョンを他のバージョンの上に構築することもできます。

uploaders / image_uploader.rb

version :small_thumb, from_version: :thumb do
    process resize_to_fill: [20, 20]
end

すでにいくつかの画像をアップロードしている場合、それらの画像にはサムネイルがありません。ただし、Railsコンソールから再作成できるため、これは問題ではありません。

rails c
Post.find_each {|post| post.image.recreate_versions!(:thumb) if post.image?}

最後に、元の画像へのリンクを含むサムネイルを表示します:

views / posts / show.html.erb

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

サーバーを起動して結果を確認してください!

検証の追加

現在、アップロードは機能していますが、ユーザー入力をまったく検証していません。もちろん、これは悪いことです。画像のみを操作する場合は、.png、.jpg、.gifの拡張子をホワイトリストに登録しましょう:

uploaders / image_uploader.rb

def extension_whitelist
    %w(jpg jpeg gif png)
end

content_type_whitelist を定義して、コンテンツタイプチェックを追加することもできます。 方法:

uploaders / image_uploader.rb

def content_type_whitelist
    /image\//
end

または、 content_type_blacklist を定義することで、実行可能ファイルなどの一部のファイルタイプをブラックリストに登録することもできます。 メソッド。

ファイルのタイプと拡張子を確認する以外に、1メガバイト未満になるように強制しましょう。そのためには、ActiveModelのファイル検証をサポートする追加のgemが必要です。

ジェムファイル

gem 'file_validators'

インストールする:

bundle install

次に、必要な検証を紹介します( titleのチェックも追加していることに注意してください およびbody 属性):

models / post.rb

validates :title, presence: true, length: {minimum: 2}
validates :body, presence: true
validates :image, file_size: { less_than: 1.megabytes }

次に行うことは、CarrierwaveのエラーメッセージにI18n変換を追加することです:

config / locales / en.yml

en:
  errors:
    messages:
      carrierwave_processing_error: "Cannot resize image."
      carrierwave_integrity_error: "Not an image."
      carrierwave_download_error: "Couldn't download image."
      extension_whitelist_error: "You are not allowed to upload %{extension} files, allowed types: %{allowed_types}"
      extension_blacklist_error: "You are not allowed to upload %{extension} files, prohibited types: %{prohibited_types}"

現在、検証エラーはどこにも表示されないので、共有パーシャルを作成しましょう:

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 / posts / _form.html.erb

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

次に、いくつかの無効なファイルをアップロードして、結果を観察してみてください。動作するはずですが、有効なファイルを選択し、タイトルまたは本文を入力しない場合でも、チェックは失敗し、エラーが表示されます。ただし、ファイルフィールドはクリアされ、ユーザーは画像を再度選択する必要があります。これはあまり便利ではありません。これを修正するには、フォームに別のフィールドを追加する必要があります。

リクエスト間でファイルを永続化する

フォームの再表示間でファイルを永続化することは、実際には非常に簡単です。あなたがする必要があるのは、新しい隠しフィールドを追加し、それをコントローラー内で許可することです:

views / shared / _form.html.erb

<%= f.label :image %>
<%= f.file_field :image %><br>
<%= f.hidden_field :image_cache %>

posts_controller.rb

params.require(:post).permit(:title, :body, :image, :image_cache)

次に、 image_cache 自動的に入力され、画像が失われることはありません。画像が正常に処理されたことをユーザーが理解できるように、サムネイルも表示すると便利な場合があります。

views / shared / _form.html.erb

<% if post.image? %>
    <%= image_tag post.image.thumb.url %>
<% end %>

画像の削除

もう1つの非常に一般的な機能は、レコードの編集時に添付ファイルを削除する機能です。 Carrierwaveでは、この機能の実装は問題ではありません。フォームに新しいチェックボックスを追加します:

views / shared / _form.html.erb

<% if post.image? %>
    <%= image_tag post.image.thumb.url %>
    <div>
      <%= label_tag :remove_image do %>
        Remove image
        <%= f.check_box :remove_image %>
      <% end %>
    </div>
<% end %>

そして、 remove_imageを許可します 属性:

posts_controller.rb

params.require(:post).permit(:title, :body, :image, :remove_image, :image_cache)

それでおしまい!画像を手動で削除するには、 remove_image!を使用します 方法:

@post.remove_image!

リモートロケーションからのアップロード

Carrierwaveは、すぐに使用できる非常に優れた機能も提供します。それは、URLによってリモートの場所からファイルをアップロードする機能です。新しいフィールドを追加し、対応する属性を許可して、この機能を紹介しましょう。

views / shared / _form.html.erb

<%= f.text_field :remote_image_url %>
<small>Enter URL to an image</small>

posts_controller.rb

params.require(:post).permit(:title, :body, :image, :remove_image, :image_cache, :remote_image_url)

それはどれくらいクールですか?変更を加える必要はまったくなく、この機能をすぐにテストできます!

複数のアップロードの操作

投稿に複数の添付ファイルを用意したいとします。現在の設定ではそれは不可能ですが、幸いなことに、Carrierwaveはそのようなシナリオもサポートしています。この機能を実装するには、シリアル化されたフィールド(SQLiteの場合)またはJSONフィールド(PostgresまたはMySQLの場合)のいずれかを追加する必要があります。私は後者のオプションを好むので、今すぐ新しいデータベースアダプタに切り替えましょう。 Gemfileからsqlite3gemを削除します 代わりにpgを追加してください:

ジェムファイル

gem 'pg'

インストールする:

bundle install

次のようにデータベース構成を変更します。

config / database.yml

default: &default
  adapter: postgresql
  pool: 5
  timeout: 5000

development:
  <<: *default
  database: upload_carrier_dev
  username: 'YOUR_USER'
  password: 'YOUR_PASSWORD'
  host: localhost

対応するPostgresデータベースを作成してから、移行を生成して適用します。

rails g migration add_attachments_to_posts attachments:json
rails db:migrate

SQLiteを使い続ける場合は、Carrierwaveのドキュメントに記載されている手順に従ってください。

次に、アップローダーをマウントします(複数形に注意してください!):

model / post.rb

mount_uploaders :attachments, ImageUploader

添付ファイルに同じアップローダーを使用していますが、もちろん、異なる構成で新しいアップローダーを生成できます。

複数ファイルフィールドをフォームに追加します:

views / shared / _form.html.erb

<div>
    <%= f.label :attachments %>
    <%= f.file_field :attachments, multiple: true %>
</div>

添付ファイルである限り フィールドには配列が含まれるため、次の方法で許可する必要があります。

posts_controller.rb

params.require(:post).permit(:title, :body, :image, :remove_image, :image_cache, :remote_image_url, attachments: [])

最後に、投稿の添付ファイルを繰り返して、通常どおりに表示することができます:

views / shared / show.html.erb

<% if @post.attachments? %>
  <ul>
    <% @post.attachments.each do |attachment| %>
      <li><%= link_to(image_tag(attachment.thumb.url, alt: 'Image'), attachment.url, target: '_blank') %></li>
    <% end %>
  </ul>
<% end %>

各添付ファイルには、 ImageUploaderで構成されたサムネイルが含まれることに注意してください。 。いいね!

クラウドストレージの使用

たとえば、Herokuではカスタムファイルを保存できないため、ファイルストレージを使用することは必ずしも便利であるとは限りません。したがって、CarrierwaveをAmazonS3クラウドストレージと組み合わせる方法を尋ねるかもしれません。まあ、それもかなり簡単な作業です。 Carrierwaveは、この機能を実装するためにfog-awsgemに依存しています:

ジェムファイル

gem "fog-aws"

インストールする:

bundle install

Carrierwaveの初期化子を作成し、クラウドストレージをグローバルに構成しましょう:

config / initializers /carrierwave.rb

CarrierWave.configure do |config|
  config.fog_provider = 'fog/aws'
  config.fog_credentials = {
      provider:              'AWS',
      aws_access_key_id:     ENV['S3_KEY'],
      aws_secret_access_key: ENV['S3_SECRET'],
      region:                ENV['S3_REGION'],
  }
  config.fog_directory  = ENV['S3_BUCKET']
end

ドキュメントに記載されている他のオプションもあります。

dotenv-rails gemを使用して環境変数を安全な方法で設定していますが、他のオプションを選択することもできます。ただし、S3キーペアが公開されていないことを確認してください。公開されていない場合は、誰でもバケットに何でもアップロードできます。

次に、 storage:fileを置き換えます 次の行:

uploaders / image_uploader.rb

storage :fog

S3とは別に、CarrierwaveはGoogleStorageとRackspaceへのアップロードをサポートしています。これらのサービスも簡単に設定できます。

結論

今日はこれでおしまい! Carrierwaveのすべての主要な機能について説明しました。これで、プロジェクトでの使用を開始できます。いくつかの追加オプションが利用できるので、ドキュメントを参照してください。

行き詰まっている場合は、遠慮なく質問を投稿してください。また、Carrierwaveのwikiを覗いてみると便利かもしれません。このウィキには、多くの一般的な質問に答える便利な「ハウツー」記事が掲載されています。

だから私と一緒にいてくれてありがとう、そして幸せなコーディング!


  1. Vue、Vuex、Railsを使用したフルスタックアプリケーションの構築

    スケーラビリティを念頭に置いてフルスタックアプリケーションを構築することは、特に、完全なタイプスクリプトをサポートする最新バージョンのVueおよびVuexを使用して構築する場合、威圧的になる可能性があります。この記事では、不健康な家畜への治療の処方を管理するCRUDアプリケーションを探索することで、APIリクエストとデータベースの相互作用を処理するVuex4.0を使用した状態管理からスケーラブルなフルスタックアプリケーションを構築するために知っておく必要のあるすべてを読者に教えます。バックエンドはRailsで構築され、フロントエンドによる統合のために基本的なCRUDAPIを公開します。 ほと

  2. Rails5でのAngularの使用

    あなたは前にその話を聞いたことがあります。分散型で完全に機能するバックエンドAPIと、通常のツールセットで作成されたフロントエンドで実行されているアプリケーションがすでにあります。 次に、Angularに移動します。または、AngularをRailsプロジェクトと統合する方法を探しているだけかもしれません。これは、この方法を好むためです。私たちはあなたを責めません。 このようなアプローチを使用すると、両方の世界を活用して、たとえばRailsとAngularのどちらの機能を使用してフォーマットするかを決定できます。 構築するもの 心配する必要はありません。このチュートリアルは、この目的のた