젬 이란?
젬은 다양하고 편리한 기능을 쉽게 쓸 수 있도록, 다른 사람들이 배포한 패키지 입니다.
루비에서는 라이브러리를 젬형태로 배포합니다. 주로 RubyGems.org 사이트에서 젬을 올리고 사용자들이 설치할 수 있습니다.
이 포스팅에서는 레일즈에서 사용자 인증 모델을 간편하게 해주는 Devise 젬과 파일 첨부를 해주는 PaperClip 젬을 실습하려 합니다.
< RubyGems.org 사진 >
예제 파일 클론하기
Devise 젬과 PaperClip 젬을 실습하기 전에 게시판 프로젝트를 클론해야 합니다. C9.IO 환경을 기준으로 하겠습니다.
Clone or download 버튼을 누르시면, .git 파일 주소가 나타납니다! .git 파일 주소의 오른쪽에 있는 버튼을 눌러 주소를 복사합니다.
그 후 C9의 Create Workspace 페이지에서 Clone from Git or Mercurial URL (optional) 텍스트에 붙여넣기 하여 워크스페이스를 만듭니다.
깃 클론을 통해 게시판 프로젝트의 파일만을 가져왔기 때문에, 이 프로젝트에 있는 젬들을 C9에서 설치해주어야 합니다.
$ bundle install
명령어로 설치합니다.
Gemfile 분석하기
Devise 젬과 PaperClip 젬을 설치하기 위해서 프로젝트 폴더에서 Gemfile 파일을 열어 소스를 확인합니다.
Gemfile 파일의 최상단에 있는 소스는 다음 명령어 입니다.
source 'https://rubygems.org'
이는 별다른 지시가 없으면 RubyGems.org 에서 원본 젬을 가져와 설치하겠다는 의미입니다.
git_source(:github) do |repo_name|
repo_name = "#{repo_name}/#{repo_name}" unless repo_name.include?("/")
"https://github.com/#{repo_name}.git"
end
또는 RubyGems.org 가 아니라 Github 의 리포지토리를 통해 젬을 설치할 수 있습니다. 이 때는 github: '리포지토리' 옵션을 넣어줘야 합니다.
1) gem 'rails', '~> 5.0.2'
2) gem 'rails', github: 'rails/rails'
첫 번째 소스는 RubyGems.org 에서 'rails' 라는 버전 '5.0.2'의 젬을 가져와 설치하겠다는 의미입니다.
반면, 두 번째 소스는 GitHub 에서 'rails/rails' 리포지토리에서 젬을 클론해와 설치하겠다는 의미입니다.
Devise 젬 설치하기
대부분의 젬파일은 GitHub 도큐먼트에서 설치법과 사용법을 알려줍니다. Devise 젬 같은 경우에도 GitHub plataformatec/devise 리포지토리에서 문서가 있어 설치법과 사용법이 나와 있습니다.
1. Gemfile 에 gem 'devise' 추가하고 $ bundle install 로 설치하기
2. $ rails generate devise:install 로 devise 기본 파일 생성하기
3. Devise 젬을 통해 User 모델 생성하기 : $ rails generate devise User
4. User 모델과 Post 모델, Comment 모델 연결하기
한 사용자는 여러 개의 게시글과, 여러 개의 댓글을 가지고 있으므로, 둘 다 1:N 관계로 설정해야 합니다.
app/models 폴더에 있는 모델 파일들을 통해 모델 관계를 설정합니다.
belongs_to 와 has_many 는 메소드이고, :user와 :post, :posts, :comments 는 심볼임에 주의!!
레일즈는 이름 규칙에 엄격하므로 하나를 의미할 때는 단수형인 :post 를, 여러개를 의미할 때는 복수형인 :posts 를 써야 하는것에 유의!!
5. DB 마이그레이션 전에, Post 와 Comment 마이그레이션 파일에 User 모델을 연결해줍시다!
db/migrate 폴더에서 Post 와 Comment 마이그레이션 파일에
t.references :user, foreign_key: true
소스를 추가합니다.
6. $ rails db:migrate 명령어로 실제 DB 파일을 생성합니다.
Devise 젬 적용하기
우선 비회원과 회원의 접근 권한을 어디까지 허용할 건지 생각해 봅시다! 비회원은 글 리스트 (post#index) 보기만 허용하고, 나머지는 회원만 접근하도록 합니다.
그리고 비회원일 때는 상단 메뉴가 로그인과 회원가입 버튼으로 놔두고, 회원일 때는 자기 이메일 표시와 로그아웃 버튼으로 변경해야 합니다.
Post 컨트롤러에서 액션마다 접근 권한을 주기 위해서는 컨트롤러에 before_action 필터로 적용해야 합니다.
before_action :authenticate_user!, except: [:index]
'authenticate_모델이름!' 메소드로 사용자 인증(로그인)을 했는지 체크할 수 있습니다.
before_action 메소드로 액션에 들어가기 전에 특정 메소드를 수행할 수 있습니다.
옵션으로 only 와 except 가 있는데, only 는 지정된 액션만 수행하도록 설정합니다.
except는 지정된 액션만 수행하지 않게 설정합니다.
넘겨줄 액션은 리스트 ( [ ] 형태 ) 로 넘겨줄 수 있습니다. 예를 들면 글 보기까지 비회원이 보게 한다면, 아래와 같이 설정합니다.
before_action :authenticate_user!, except: [:index, :show]
Post 컨트롤러에서 게시글을 모델에 저장할 때, 사용자 정보도 넘겨주어야 어떤 사용자가 어떤 게시글들을 만들었는지 보여줄 수 있습니다.
'current_모델' 메소드를 통해서 현재 로그인한 모델의 정보를 가져올 수 있습니다. 따라서 Post 모델을 작성할 때 user 속성에 넣어 생성한 사람의 정보를 저장할 수 있습니다. 또 모델 관계를 설정했기 때문에, 반대로 사용자가 작성한 게시글들을 보여줄 수 있습니다.
Comment 컨트롤러에서도 똑같이 before_action 필터를 달아주고, 모델의 user 속성에 현재 로그인한 유저의 정보를 저장하도록 합니다!!
두 번째로, 상단 메뉴를 수정해 봅니다. 상단 메뉴는 app/views/layouts/application.html.erb 파일에 있습니다. 로그인과 회원가입, 로그아웃 주소를 수정하기 전에 devise 라우팅이 어떻게 되어있는지 확인해 봅시다!
$ rails routes
명령어로 현재 적용된 라우팅을 알 수 있습니다.
로그인을 할 수 있는 주소는 /users/sign_in 이고, 회원가입 주소는 /users/sign_up, 로그아웃 주소는 /users/sign_out 입니다.
그런데 /users/sign_out 주소는 DELETE 동작으로 넘겨야 되는데, 이를 GET 동작으로 설정에서 바꿀 수 있습니다. config/initializers/devise.rb 파일에서
config.sign_out_via = :delete 를
config.sign_out_via = :get
으로 수정해서 저장한 뒤, 다시 서버를 재가동 시켜봅니다!!
( 서버 설정을 바꿨다면, 재가동 시켜야 적용이 됩니다. )
$ rails routes
명령어로 다시 확인을 해보면, GET 으로 바뀐것을 확인할 수 있습니다.
이제 application.html.erb 에서 메뉴를 수정해봅니다.
'user_signed_in?' 메소드로 먼저 비회원인지 회원인지에 따라 다른 메뉴를 생성하도록 합니다. 회원이면, 이메일 표시와 로그아웃 메뉴를 띄우고 비회원이면, 회원가입 메뉴와 로그인 메뉴를 띄우게 합니다.
첫 번째 사진은 로그인 하기 전, 비회원 메뉴입니다. 로그인 버튼과 회원가입 버튼이 메뉴에 배치되어 있습니다.
두 번째 사진은 회원가입 페이지 이고, 최소 비밀번호는 6글자로 설정되어 있습니다.
세 번째 사진은 로그인 후, 회원 메뉴입니다. 현재 로그인된 계정의 이메일 정보와 로그아웃 버튼이 배치되어 있습니다.
여담으로, 최소 비밀번호 글자와 최대 비밀번호 글자를 변경하려면 아까와 마찬가지로 config/initializers/devise.rb 파일에서 config.password_length 를 수정하고 서버를 재가동 시키면 됩니다.
최소글자 수를 4, 최대글자 수를 64로 변경했습니다. 회원가입 페이지에서 수정된 것을 볼 수 있습니다.
로그인, 회원가입 페이지 수정하기
Devise 젬에서의 로그인과 회원가입 페이지는 정말 기본적인 양식(Form)만 제공해줍니다. 이를 커스터마이징 하기 위해서는 다음과 같은 명령어로 Devise 템플릿 파일을 생성시켜야 합니다.
$ rails generate devise:views
로그인 페이지는 app/views/devise/sessions/new.html.erb 파일이고, 회원가입 페이지는 app/views/devise/registrations/new.html.erb 파일입니다.
자세한 소스는 이번 포스팅 예제를 참고해 봅니다.
이번 포스팅 예제 워크스페이스는 GitHub 에 올려두겠습니다. 링크는 게시글 맨 아래에 있습니다.
app/views/post/index.html.erb 에서 테이블 태그의 thead 태그 안에 <th width="120px">작성자</th> 을 추가하고, tbody 태그 안에
<td>
<%= onePost.user.email %>
</td>
으로 작성자를 표시하게 했습니다.
마찬가지로 댓글 부분도 작성자를 표시하게 했습니다. app/views/post/show.html.erb 파일에서 <tbody> 태그 안에 넣어줬습니다.
닉네임 추가하기
Devise 젬에서도 이메일, 비밀번호 이외에 다른 속성을 추가할 수 있습니다. 닉네임을 추가해봅니다.
db/migrate 폴더의 User 마이그레이션 파일에 아래 소스를 추가해봅니다.
그런 다음, app/views/devise/registrations/new.html.erb 파일에 nickname 입력부분을 추가해봅니다.
그 후, DB 드랍 후 다시 생성합니다!
app/controllers/application_controller.rb 파일에서 회원가입 시 nickname 정보가 들어오도록 설정해 주어야 합니다.
이후 User 모델에 Nickname 속성을 사용할 수 있습니다.
메뉴와 글작성자, 댓글작성자에 user.nickname 속성을 넣어봤습니다.
이미지를 첨부해보자
먼저 PaperClip 젬이 이미지를 제어해주는 ImageMagick 라이브러리를 사용합니다. 따라서, 개발환경에 ImageMagick 라이브러리가 다운로드 되있어야 합니다. C9 환경에서는 리눅스 환경입니다! 아래 명령어로 ImageMagick 라이브러리를 다운로드 받겠습니다.
$ sudo apt-get update
$ sudo apt-get install imagemagick -y
첫 번째 명령어로 개발환경에서 업데이트를 해주어야 imagemagick 을 다운로드 받을 수 있습니다.
업데이트를 안하시고, 바로 설치하시면 위와 같이 다운로드가 실패합니다.
< 현재 환경 패키지 업데이트 >
< ImageMagick 라이브러리 설치 >
PaperClip 젬 설치
Gemfile 파일에 gem 'devise' 밑에 PaperClip 젬을 넣어 설치합니다.
세 번째 명령어는 git 주소를 통해서 젬을 다운로드 받습니다.
네 번째 명령어는 github 옵션을 통해서 젬을 다운로드 받습니다.
Gemfile 파일 저장 후 설치 명령어는 위와 같이
$ bundle install
입니다.
< 설치된 paperclip 젬 >
PaperClip 젬 설정하기
Post 모델(app/models/post.rb)에 이미지 파일을 첨부한다는 설정을 해주어야 합니다!
class Post < ApplicationRecord
has_attached_file :avatar, styles: { medium: "300x300>", thumb: "100x100>" }, default_url: "/images/:style/missing.png"
validates_attachment_content_type :avatar, content_type: /\Aimage\/.*\z/
belongs_to :user
has_many :comments
end
이제, 게시글을 올리거나 편집할 때 이미지 파일을 업로드 하는 폼을 만들어야 합니다.
app/views/post/new.html.erb, show.html.erb, edit.html.erb 파일을 수정해봅시다.
먼저, new.html.erb 파일과 edit.html.erb 파일에서 다음과 같이 form_tag 헬퍼 메소드에서 multipart 옵션을 추가해 줍시다.
< new.html.erb >
< edit.html.erb >
파일을 첨부하여 서버로 전송하기 위해서는 multipart 형식으로 보내주어야 합니다.
< 변경된 Form 태그 속성... enctype 속성이 추가되어 있다. >
글쓰기 페이지(new.html.erb)에서 글 본문과 목록으로 돌아가기 사이에 파일 첨부 폼을 만들었습니다.
< 전송 이름을 avatar 으로 짓고, input type 을 file 로 했습니다. >
< 추가된 파일 입력 양식(폼) >
이제, Post 컨트롤러의 create 액션에서 첨부된 이미지 파일을 불러와서 Post 모델에 저장하는 작업을 해주어야 합니다.
avatar 이름으로 업로드된 파일이 서버로 넘겨옵니다. 만약에, 업로드된 파일이 있을 경우에만 Post 모델에 이미지 파일을 저장시킵니다.
그 다음에 show.html.erb 파일에서 Post 모델에 저장된 이미지가 있다면 표시해주고, 없다면 표시해주지 않게 작업해 줍니다.
이미지 파일의 주소는 '모델.avatar.url' 로 가져올 수 있습니다. 또한 업로드할 때, 설정된 medium 과 thumb 사이즈로도 넘어갔으므로, '모델.avatar.url(:medium)' 과 '모델.avatar.url(:thumb)' 으로 작은 사이즈의 이미지 파일의 주소도 가져올 수 있습니다.
< 업로드된 이미지 파일이 있을 경우의 show 페이지 >
< 업로드된 이미지 파일이 없을 경우의 show 페이지 >
이제, edit.html.erb 파일을 수정하여 이미지 파일을 재 업로드 할 수 있게 해줍니다.
avatar 이름의 file 양식을 추가해주고, 이미 Post 모델의 이미지가 있으면 아래에 표시하도록 수정했습니다.
처음의 모든 글을 불러올 때, 이미지 파일이 업로드 되어 있으면 옆에 사진 아이콘이 뜨도록 설정해 봤습니다.
일단 급한대로, 네이버 카페의 그림 아이콘과 css를 따왔습니다.
app/assets/stylesheets/post.scss 파일에다가 css 를 넣어줍니다.
input {
border: 0!important;
background-color: transparent;
}
.list-i-img {
width: 13px;
height: 12px;
background: url(http://cafeimgs.naver.net/cafe4/ico-img.gif) 0 0 no-repeat;
}
그리고 index.html.erb 파일에서 모든 글을 불러올 때, 이미지가 있으면 그림 아이콘을 옆에다 달게 해줍니다.
< 적용한 모습 >
이렇게 해서 PaperClip 젬을 이용해서 이미지 파일을 업로드 해봤습니다!
PaperClip 젬으로 유저의 프로필 사진도 업로드하는 등 여러 방면으로 활용이 가능한 젬입니다!
---
프로젝트 Github 주소 : https://github.com/kor-Chipmunk/devisepaperclip
'Back-End > Back-End 자료실' 카테고리의 다른 글
[Ruby On Rails] pg Gem 설치 오류 해결하기 (0) | 2018.05.21 |
---|---|
REST API: PUT & PATCH (0) | 2018.05.08 |
REST API: POST & PUT (0) | 2018.05.08 |
CoC (Convention over Configuration) (0) | 2018.05.08 |
[ Ruby on Rails ] 시간대 서울로 맞추기 ( Timezone Seoul ) (2) | 2016.08.22 |
댓글