Computer >> 컴퓨터 >  >> 프로그램 작성 >> Ruby

Rails 및 Carrierwave로 업로드하기

이것은 "Rails로 업로드" 시리즈의 또 다른 기사입니다. 오늘 우리는 가장 인기 있는 Rails용 파일 업로드 솔루션 중 하나인 Carrierwave를 만날 것입니다. Carrierwave는 시작하기 쉽고 바로 사용할 수 있는 기능이 많으며 커뮤니티 구성원이 작성한 수십 개의 "방법" 기사를 제공하므로 길을 잃지 않기 때문에 저는 Carrierwave를 좋아합니다.

이 문서에서는 다음을 수행하는 방법을 배웁니다.

  • Carrierwave를 Rails 앱에 통합
  • 검증 추가
  • 요청 간에 파일 유지
  • 파일 제거
  • 썸네일 생성
  • 원격 위치에서 파일 업로드
  • 여러 파일 업로드 도입
  • 클라우드 스토리지 지원 추가

이 기사의 소스 코드는 GitHub에서 사용할 수 있습니다. 즐겁게 읽으세요!

기초 마련

항상 그렇듯이 새 Rails 애플리케이션을 만드는 것으로 시작하세요.

rails new UploadingWithCarrierwave -T

이 데모에서는 Rails 5.0.2를 사용할 것입니다. Carrierwave 1은 Rails 4+ 및 Ruby 2만 지원합니다. 여전히 Rails 3을 사용 중이라면 Carrierwave 버전 0.11을 연결하세요.

Carrierwave가 작동하는 모습을 보기 위해 Post 모델. 다음과 같은 주요 속성을 갖습니다.

  • title (string )
  • body (text )
  • image (string ) - 이 필드에는 게시물에 첨부된 이미지(정확하게는 파일 이름)가 포함됩니다.

새 마이그레이션 생성 및 적용:

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

일부 경로 설정:

config/routes.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

이제 색인 을 만들어 보겠습니다. 보기:

보기/게시물/index.html.erb

<h1>Posts</h1>

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

<%= render @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

이제 앱/업로더 내부에서 , image_uploader.rb라는 새 파일을 찾을 수 있습니다. . 여기에는 몇 가지 유용한 설명과 예제가 있으므로 시작하는 데 사용할 수 있습니다. 이 데모에서는 ActiveRecord를 사용하지만 Carrierwave는 Mongoid, Sequel 및 DataMapper도 지원합니다.

다음으로 포함하거나 마운트 해야 합니다. 이 업로더를 모델에 추가:

모델/post.rb

mount_uploader :image, ImageUploader

업로더는 이미 정상적인 기본 설정을 가지고 있지만 최소한 업로드된 파일을 저장할 위치를 선택해야 합니다. 지금은 파일 저장소를 사용하겠습니다.

업로더/image_uploader.rb

storage :file

기본적으로 파일은 공개/업로드 디렉토리이므로 버전 관리 시스템에서 제외하는 것이 가장 좋습니다.

.gitignore

public/uploads

store_dir을 수정할 수도 있습니다. 업로더 내부의 메소드를 사용하여 다른 위치를 선택하세요.

이 시점에서 파일 업로드를 시작하기 위해 부분적으로 새 보기와 양식을 만들 수 있습니다.

보기/게시물/new.html.erb

<h1>Add post</h1>

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

보기/게시물/_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를 허용했으므로 수정할 필요가 없습니다. 속성.

마지막으로 편집 보기를 만듭니다.

보기/게시물/edit.html.erb

<h1>Edit post</h1>

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

그게 다야! 서버를 부팅하고 이미지가 있는 게시물을 만들 수 있습니다. 문제는 이 이미지가 어디에도 표시되지 않는다는 것이므로 다음 섹션으로 이동하여 쇼 페이지를 추가합시다!

이미지 표시

따라서 아직 만들지 않은 유일한 보기는 show입니다. . 지금 추가:

보기/게시물/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는 ImageMagick의 도움으로 이미지를 조작하는 데 사용되는 RMagick 및 MiniMagick 보석을 기본적으로 지원합니다. ImageMagick은 기존 이미지를 편집하고 새 이미지를 생성할 수 있는 오픈 소스 솔루션이므로 계속하기 전에 다운로드하여 설치해야 합니다. 다음으로 두 개의 보석 중 하나를 자유롭게 선택할 수 있습니다. MiniMagick은 설치가 훨씬 쉽고 지원이 더 잘 되기 때문에 계속 사용하겠습니다. 

젬파일

gem 'mini_magick'

실행:

bundle install

그런 다음 업로더에 MiniMagick을 포함합니다.

업로더/image_uploader.rb

include CarrierWave::MiniMagick

이제 업로더에 새 버전을 도입하기만 하면 됩니다. 버전 의 개념 (또는 스타일)은 많은 파일 업로드 라이브러리에서 사용됩니다. 이는 단순히 원본 첨부 파일을 기반으로 하는 추가 파일이 예를 들어 다른 치수 또는 형식으로 생성된다는 것을 의미합니다. thumb라는 새 버전을 소개합니다. :

업로더/image_uploader.rb

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

원하는 만큼 여러 버전을 사용할 수 있으며 다른 버전 위에 빌드할 수도 있습니다.

업로더/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?}

마지막으로 원본 이미지에 대한 링크와 함께 미리보기 이미지를 표시합니다.

보기/게시물/show.html.erb

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

서버를 부팅하고 결과를 관찰하십시오!

검증 추가

현재 우리의 업로드는 작동하지만 사용자 입력을 전혀 확인하지 않고 있습니다. 이는 물론 나쁜 일입니다. 이미지로만 작업하려는 한 .png, .jpg 및 .gif 확장자를 허용 목록에 추가합니다.

업로더/image_uploader.rb

def extension_whitelist
    %w(jpg jpeg gif png)
end

content_type_whitelist를 정의하여 콘텐츠 유형 검사를 추가할 수도 있습니다. 방법:

업로더/image_uploader.rb

def content_type_whitelist
    /image\//
end

또는 content_type_blacklist를 정의하여 일부 파일 형식(예:실행 파일)을 블랙리스트에 추가할 수 있습니다. 방법.

파일의 형식과 확장자를 확인하는 것 외에 1메가바이트 미만으로 강제 실행해보자. 그렇게 하려면 ActiveModel에 대한 파일 유효성 검사를 지원하는 추가 gem이 필요합니다.

젬파일

gem 'file_validators'

설치:

bundle install

이제 원하는 유효성 검사를 소개합니다(titlebody 속성):

모델/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}"

현재 어디에도 유효성 검사 오류가 표시되지 않으므로 공유 부분을 생성해 보겠습니다.

보기/공유/_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 %>

이 부분을 양식 내에서 사용:

보기/게시물/_form.html.erb

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

이제 잘못된 파일을 업로드하고 결과를 관찰하십시오. 작동해야 하지만 유효한 파일을 선택하고 제목이나 본문을 채우지 않으면 검사가 계속 실패하고 오류가 표시됩니다. 그러나 파일 필드가 지워지고 사용자가 이미지를 다시 선택해야 하므로 그다지 편리하지 않습니다. 이 문제를 해결하려면 양식에 다른 필드를 추가해야 합니다.

요청 간에 파일 유지

양식을 다시 표시하는 동안 파일을 유지하는 것은 실제로 매우 쉽습니다. 새로운 숨겨진 필드를 추가하고 컨트롤러 내부에서 허용하기만 하면 됩니다.

보기/공유/_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 자동으로 채워지고 이미지가 손실되지 않습니다. 사용자가 이미지가 성공적으로 처리되었음을 이해할 수 있도록 미리보기 이미지도 표시하는 것이 도움이 될 수 있습니다. 

보기/공유/_form.html.erb

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

이미지 제거

또 다른 매우 일반적인 기능은 레코드를 편집할 때 첨부 파일을 제거하는 기능입니다. Carrierwave를 사용하면 이 기능을 구현하는 데 문제가 없습니다. 양식에 새 확인란 추가:

보기/공유/_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을 통해 원격 위치에서 파일을 업로드하는 기능입니다. 이제 새 필드를 추가하고 해당 속성을 허용하여 이 기능을 소개하겠습니다. 

보기/공유/_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 에서 sqlite3 gem을 제거합니다. 대신 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의 설명서에 나열된 지침을 따르십시오.

이제 업로더를 마운트합니다(복수형에 주의하세요!):

모델/포스트.rb

mount_uploaders :attachments, ImageUploader

첨부 파일에 동일한 업로더를 사용하고 있지만 물론 다른 구성으로 새 업로더를 생성할 수 있습니다.

양식에 다중 파일 필드 추가:

보기/공유/_form.html.erb

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

attachments만큼 필드에 배열이 포함될 예정이므로 다음과 같은 방식으로 허용해야 합니다.

posts_controller.rb

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

마지막으로 게시물의 첨부 파일을 반복하여 평소와 같이 표시할 수 있습니다.

보기/공유/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를 Amazon S3 클라우드 스토리지와 결합하는 방법에 대해 질문할 수 있습니다. 음, 그것도 꽤 쉬운 작업입니다. Carrierwave는 이 기능을 구현하기 위해 Fog-aws gem에 의존합니다.

젬파일

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을 교체합니다. 줄:

업로더/image_uploader.rb

storage :fog

S3 외에도 Carrierwave는 Google Storage 및 Rackspace에 대한 업로드를 지원합니다. 이러한 서비스도 쉽게 설정할 수 있습니다.

결론

오늘은 여기까지! Carrierwave의 모든 주요 기능을 다루었으므로 이제 프로젝트에서 사용할 수 있습니다. 몇 가지 추가 옵션을 사용할 수 있으므로 설명서를 찾아보십시오.

막히면 주저하지 말고 질문을 게시하십시오. 또한 많은 일반적인 질문에 답변하는 유용한 "방법" 문서를 호스팅하는 Carrierwave의 Wiki를 살펴보는 것이 유용할 수 있습니다.

그럼 저와 함께 해주셔서 감사하고 행복한 코딩 되세요!