N10. post 이미지 업로드 Carrierwave 적용
파일업로드를 담당하는 carrierwave 세팅을 해보자.
이미지를 업로드해 아바타 이미지 추가, 포스트 이미지 추가가 가능하다.
gemfile에
gem 'carrierwave'
추가
콘솔에
ubuntu:~/environment/noar (master) $ bundle
The dependency tzinfo-data (>= 0) will be unused by any of the platforms Bundler is installing for. Bundler is installing for ruby but the dependency is only for x86-mingw32, x86-mswin32, x64-mingw32, java. To add those platforms to the bundle, run `bundle lock --add-platform x86-mingw32 x86-mswin32 x64-mingw32 java`.
Fetching gem metadata from https://rubygems.org/............
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Using rake 13.0.1
Using concurrent-ruby 1.1.6
Using i18n 1.8.3
Using minitest 5.14.1
Using thread_safe 0.3.6
Using tzinfo 1.2.7
Using activesupport 5.0.7.2
Using builder 3.2.4
Using erubis 2.7.0
Using mini_portile2 2.4.0
Using nokogiri 1.10.9
Using rails-dom-testing 2.0.3
Using crass 1.0.6
Using loofah 2.5.0
Using rails-html-sanitizer 1.3.0
Using actionview 5.0.7.2
Using rack 2.2.2
Using rack-test 0.6.3
Using actionpack 5.0.7.2
Using nio4r 2.5.2
Using websocket-extensions 0.1.5
Using websocket-driver 0.6.5
Using actioncable 5.0.7.2
Using globalid 0.4.2
Using activejob 5.0.7.2
Using mini_mime 1.0.2
Using mail 2.7.1
Using actionmailer 5.0.7.2
Using activemodel 5.0.7.2
Using arel 7.1.4
Using activerecord 5.0.7.2
Fetching public_suffix 4.0.5
Installing public_suffix 4.0.5
Fetching addressable 2.7.0
Installing addressable 2.7.0
Using execjs 2.7.0
Using autoprefixer-rails 9.7.6
Using bcrypt 3.1.13
Using bindex 0.8.1
Using bundler 1.17.2
Using byebug 11.1.3
Fetching mini_magick 4.10.1
Installing mini_magick 4.10.1
Using ffi 1.13.1
Fetching ruby-vips 2.0.17
Installing ruby-vips 2.0.17
Fetching image_processing 1.11.0
Installing image_processing 1.11.0
Fetching mimemagic 0.3.5
Installing mimemagic 0.3.5
Fetching carrierwave 2.1.0
Installing carrierwave 2.1.0
Using coffee-script-source 1.12.2
Using coffee-script 2.4.1
Using method_source 1.0.0
Using thor 1.0.1
Using railties 5.0.7.2
Using coffee-rails 4.2.2
Using orm_adapter 0.5.0
Using responders 3.0.1
Using warden 1.2.8
Using devise 4.7.2 from https://github.com/plataformatec/devise.git (at master@0e33f55)
Using jbuilder 2.10.0
Using jquery-rails 4.4.0
Using rb-fsevent 0.10.4
Using rb-inotify 0.10.1
Using listen 3.0.8
Using materialize-sass 1.0.0
Using puma 3.12.6
Using sprockets 3.7.2
Using sprockets-rails 3.2.1
Using rails 5.0.7.2
Using sass-listen 4.0.0
Using sass 3.7.4
Using tilt 2.0.10
Using sass-rails 5.0.7
Using spring 2.1.0
Using spring-watcher-listen 2.0.1
Using sqlite3 1.3.13
Using turbolinks-source 5.2.0
Using turbolinks 5.2.1
Using uglifier 4.2.0
Using web-console 3.7.0
Bundle complete! 18 Gemfile dependencies, 76 gems now installed.
Use `bundle info [gemname]` to see where a bundled gem is installed.
carrierwave는 uploader라는걸로 파일 업로드를 관리한다.
한 종류의 파일에 대해서 하나의 업로더를 만드는게 기본규칙이다.
그래서 우리는 유저모델에 쓸 아바타 이미지를 업로드하는 업로더를 하나 만들거고
포스트에 이미지를 추가하는 업로더를 하나 만들거다
서로 다로 만드는 이유는, 아바타의 경우 썸네일을 생성할 것이기 때문이다.
ubuntu:~/environment/noar (master) $ rails g uploader Avatar
Running via Spring preloader in process 2893
create app/uploaders/avatar_uploader.rb
ubuntu:~/environment/noar (master) $ rails g uploader PostImage
Running via Spring preloader in process 2921
create app/uploaders/post_image_uploader.rb
업로더가 잘 추가됐다.
이제 유저의 테이블과 포스트 테이블에 아바타와 포스트이미지를 올릴 수 있는 컬럼을 하나 추가해야한다.
스트링타입으로 추가하면됨
이를 마이그래이션 파일 하나로 추가해보도록 하자
ubuntu:~/environment/noar (master) $ rails g migration AddImageToUsersAndPosts
Running via Spring preloader in process 3024
invoke active_record
create db/migrate/20200705042853_add_image_to_users_and_posts.rb
class AddImageToUsersAndPosts < ActiveRecord::Migration[5.0]
def change
add_column :users, :avatar, :string
add_column :posts, :image, :string
end
end
파일들은 project_name/public 에 보관될 것이기 때문에 그 주소만 저장하면 된다.(carrierwave의 uploader가 알아서 해준다.)
ubuntu:~/environment/noar (master) $ rake db:migrate
== 20200705042853 AddImageToUsersAndPosts: migrating ==========================
-- add_column(:users, :avatar, :string)
-> 0.0055s
-- add_column(:posts, :image, :string)
-> 0.0003s
== 20200705042853 AddImageToUsersAndPosts: migrated (0.0078s) =================
mount_uploader :avatar, AvatarUploader
mount_uploader :image, PostImageUploader 추가
class User < ApplicationRecord
# Include default devise modules. Others available are:
# :confirmable, :lockable, :timeoutable, :trackable and :omniauthable
devise :database_authenticatable, :registerable,
:recoverable, :rememberable, :validatable
has_many :posts
has_many :liked
# 1:N 관계인 likes를 이용해서 Post와 N:N 관계를 구현
# 특정 유저가 좋아요를 누른 posts를 얻을 수 있음.
# ex) user.likes_posts
#유저입장에서 좋아하는 글을 가져오는데,
#가져올 때 Likes를 토대로 찾게되고,
#그 속에서 post만 묶어서 보여준다.(그 출처는 post다)
has_many :liked_posts, through: :likes, source: :post
has_many :comments
mount_uploader :avatar, AvatarUploader
#User 모델의 한 객체에 대해 특정 글에 대한 좋아요 유무를 확인
def is_like?(post)
Like.find_by(user_id: self.id, post_id: post.id).present?
end
end
class Post < ApplicationRecord
belongs_to :user
has_many :likes
# 1:N 관계인 likes를 이용해서 User와 N:N 관계를 구현
# 특정 글에 좋아요를 누른 users를 얻을 수 있음.
# ex) post.liked_users
has_many :liked_users, through: :likes, source: :user
has_many :comments
mount_uploader :image, PostImageUploader
end
이것으로 파일을 업로드 받을 수 있는 상태가 되었다.
이제 컨트롤러와 뷰를 꾸며서 이미지 업로드를 하고 사이즈 조절을 하도록 하자.
먼저 포스트에 이미지를 업로드해보자
views/posts/new.html.erb
<div class="container">
<div class="row">
<div class="card col s12">
<div class="card-content">
<div class="card-title">
새 글 작성하기
</div>
<!--이미지를 추가하기 위해 멀티파트 적용-->
<%= form_tag posts_path, multipart :ture do %>
<div class="imput-field">
<%= file_field_tag :image %>
</div>
<div class="input-field">
<%=text_area_tag :content, nil, class: "materialize-textarea", placeholder: "무슨 생각을 하고 있나요?" %>
</div>
<div class="input-field">
<%= button_tag "작성하기", class: "btn" %>
</div>
<% end %>
</div>
</div>
</div>
</div>
controllers/post_controller.rb
class PostsController < ApplicationController
before_action :authenticate_user!
before_action :check_ownership, only: [:edit, :update, :destroy]
respond_to :html, :json
...
def create
#new_post라는 임시변수를 만들고
#Post 모델에서 새로운 객체를 생성해서
#user_id: 는 현재 로그인한 사람의 id를 넣고
#내용은 파리미터로 온 content를 넣어서 저장해주겠다.
#views/posts/new.html.erb에서 넘어온 image를 carrierwave가 처리
new_post = Post.new(user_id: current_user.id,
content: params[:content],
image: params[:image])
if new_post.save
redirect_to root_path
else
redirect_to new_post_path
end
end
...
end
public폴더에 잘 올라간걸 볼 수 있다.
이제 이를 view에 표현해보도록 하자
<div class="card">
<div class="card-content">
<!-- 해당포스트의 작성자의 이름을 출력 -->
<span class="card-title"><%= post.user.name %></span>
<span><%=post.created_at %></span>
<div class="card-image">
<% if post.image.url %>
<img src="<%= post.image.url %>">
<% end %>
</div>
<p class="pre-line"><%= post.content %></p>
</div>
...
</div>
이미지를 원본으로 올리면 트래픽이 너무 많이 발생할 수 있다.
이를 해결하기위해 이미지프로세싱을 해주는 mini_magick 를 사용하자
gemfile에 gem 'mini_magick'추가
bundle 명령어 실행
class PostImageUploader < CarrierWave::Uploader::Base
# Include RMagick or MiniMagick support:
# include CarrierWave::RMagick
include CarrierWave::MiniMagick
# Choose what kind of storage to use for this uploader:
storage :file
# storage :fog
# Override the directory where uploaded files will be stored.
# This is a sensible default for uploaders that are meant to be mounted:
def store_dir
"uploads/#{model.class.to_s.underscore}/#{mounted_as}/#{model.id}"
end
...
# Process files as they are uploaded:
# process scale: [200, 300]
process :resize_to_limit => [1024, 768]
...
end
c9에 imagemagick 설치
ubuntu:~/environment $ sudo apt-get install imagemagick
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following additional packages will be installed:
fontconfig fonts-droid-fallback fonts-noto-mono ghostscript
gsfonts hicolor-icon-theme imagemagick-6-common
imagemagick-6.q16 libcairo2 libcupsfilters1 libcupsimage2
libdatrie1 libdjvulibre-text libdjvulibre21 libfftw3-double3
libgraphite2-3 libgs9 libgs9-common libharfbuzz0b libijs-0.35
libilmbase12 libjbig0 libjbig2dec0 liblqr-1-0
libmagickcore-6.q16-3 libmagickcore-6.q16-3-extra
libmagickwand-6.q16-3 libnetpbm10 libopenexr22 libpango-1.0-0
libpangocairo-1.0-0 libpangoft2-1.0-0 libpaper-utils
libpaper1 libpixman-1-0 libthai-data libthai0 libtiff5
libwmf0.2-7 libxcb-render0 libxcb-shm0 netpbm poppler-data
...
Setting up imagemagick (8:6.9.7.4+dfsg-16ubuntu6.8) ...
Setting up libpangocairo-1.0-0:amd64 (1.40.14-1ubuntu0.1) ...
Setting up libmagickcore-6.q16-3-extra:amd64 (8:6.9.7.4+dfsg-16ubuntu6.8) ...
Processing triggers for mime-support (3.60ubuntu1) ...
Processing triggers for libc-bin (2.27-3ubuntu1) ...
Processing triggers for man-db (2.8.3-2ubuntu0.1) ...
이렇게 하고 이번엔 큰 사이즈의 이미지를 올려보겠다.
업로드된 이미지를 다운받아보면 잘 리사이징 된걸 확인할 수 있다. (intrinsic : 1024 x 576 pixels)