티스토리 뷰
Ruby on Rails : 게시물 삭제 기록 남기기 [Gem : paranoia]
나른한 하루 2019. 11. 5. 03:29해당 글은 https://blog.naver.com/kbs4674/221052897085 로 부터 게시글이 이전되었습니다.
사이트 운영자는 자신의 홈페이지를 운영하면서 홈페이지 내 데이터가 삭제된다면, 그것이 그냥 삭제되도록 냅두는것이 아닌 삭제된 데이터에 대해 기록이 남겨져야 할 이유가 있습니다.
나중에 게시글 내 욕설로 인해 피해자가 가해자에게 고소를 하면, 게시글을 관리하는 사이트 운영자는 고소의 시발점이 되는 (삭제된) 자료를 경찰이 요구를 하면 해당 게시글의 (삭제된) 기록에 대해 보여줘야 할 의무가 있기 때문입니다.
그래서, 이번 시간에는 삭제된 데이터를 보관하는방법에 대해 알아보고자 합니다.
참고로 해당 Gem 기술에 있어서도 명칭이 존재합니다, 이러한 방식을 Soft Delete 라고 합니다.
참고
- 본 설명은 Post Scaffold를 기반으로 작성됩니다.
- 이번 기능은 결과 확인을 위해 rails_db Gem이 깔려있어야 하는 기능입니다. [참고]
- Controller에서 삭제를 담당하는 def 명칭이 'destroy'여야 합니다. 이 명칭이 아니면 아마 이 기능에 있어 문제가 될 수 있습니다.
- 삭제 후, 삭제된 데이터 DB 보존 : Paranoia (Soft Delete)
1. Gemfile 에서 다음 내용을 입력합니다.
gem 'paranoia'
그리고 Gem을 설치해주세요.
bundle install
2. 새로운 테이블의 컬럼을 생성합니다.
rails g migration AddDeletedAtTo[DB 삭제 기록을 남길 모델 명] deleted_at:datetime
저같은 경우는 게시판 관련 테이블 명이 posts 라서 다음과 같이 입력했습니다.
rails g migration AddDeletedAtToPost deleted_at:datetime
입력을 하면 새로운 migrate 파일이 생성이 되고, 아래와 같이 구성됩니다.
(Column과 index가 동시에 생성)
class AddDeletedAtToPosts < ActiveRecord::Migration[5.2]
def change
add_column :posts, :deleted_at, :datetime
end
end
3. 입력 후, 새로운 컬럼에 대해 schema에 적용해줍니다.
rake db:migrate
4. app/model/post.rb 로 이동하시고, 다음 내용을 추가 입력해 줍니다.
class Post < ApplicationRecord
acts_as_paranoid
...
end
5. 이제 준비가 끝났습니다!
1) 게시글을 삭제해보세요.
홈페이지에서 겉으로 보면 게시글은 당연히 안보입니다.
2) 게시글 삭제 후, rails_db Gem을 통해 DB정보를 보여주는 사이트로 가서 post에 대한 Table을 보면
deleted_at이라는 새로운 컬럼(Column)이 생겨난 것을 확인할 수 있습니다.
그리고 Deleted at 컬럼에 삭제된 게시물에 대한 삭제 시간 및 Table에 보존되어있는것을 보실 수 있습니다.
※ 원래는 게시글이 삭제되면, 삭제시간이 기록이 안되고, DB Table에서도 기록이 다 사라집니다.
참고
개인적으로, Devise의 user.rb 모델에는 Paranoia를 적용하지 않으면 좋을 것 같습니다.
일단, 적용은 되는데 A 회원이 가입 및 탈퇴를 하고, 새로운 회원가입 시 A회원이 썼던 이메일 등을 재탕하고 가입을 시도하면 과거의 기록을 갖고있다 보니 충돌(?) 문제 때문인지 회원가입이 안되고, 오류가 발생합니다.
- 이미 삭제된 데이터 불러오기
삭제된 데이터를 확인하는 방법은 Rails_db 메뉴를 통해 확인하는 방법은 있으나, Rails_db는 어디까지나 개발 때에만 쓰이는 메뉴이다 보니 이 것 만으로는 한계가 있습니다.
If you want to find all records, even those which are deleted:
[모델].with_deleted
Paranoia Gem을 제공해주는 Github 사이트에 가면 위와같은 문구를 확인할 수 있습니다.
Gem에서 지원하는 with_deleted 메소드를 통해 '삭제된 기록에 대해서도 함께 보여지게 한다.' 라는 의미인데요.
간단하게 위 문구대로 한번 적용을 해볼까요?
단순히 View에서
[변수].each do |post|
에다가 단 한 가지의 메소드 문구만 적용하면 됩니다.
예를들어서 Post Scaffod에 적용을 한다면..
## app/views/posts/index.html.erb
<% @posts.with_deleted.each do |post| %>
...
<% end %>
위와같이 .each do 앞에 .with_deleted 를 적용시키면 됩니다.
그럼 삭제됐던 게시글이 다시 목록에 보여집니다.
하지만 완전히 복구된건 아닙니다. 게시물에 접근을 하면
없는 데이트라 뜨면서 오류가 발생합니다.
- 삭제된 데이터 복구하기
위 사례에서 봤다싶이 삭제된 데이터를 단순히 불러와서는 복구가 되진 않습니다.
If you want to restore a record:
Model.restore(id)
# or
Model.restore
paranoia Github 공식 문서에 따르면 복구방법은 위와같은 방법을 하면 된다고 안내되어있습니다.
위 설명을 참고로 저도 한번 따라해보겠습니다.
1. 목록 view에서 다음과 같이 내용을 수정합니다.
## app/views/posts/index.html.erb
<% if post.deleted? %>
<%= link_to '복구', "/posts/recovery/#{post.id}" %>
<% end %>
## app/views/posts/index.html.erb
## 적용 예시
<% @posts.with_deleted.each do |post| %>
<tr>
... (내용 생략) ...
<% if post.deleted? %>
<td><%= link_to '복구', "/posts/recovery/#{post.id}" %></td>
<% end %>
</tr>
<% end %>
2. Posts Controllers에 다음 액션을 추가합니다.
## app/controllers/posts_controller.rb
class PostsController < ApplicationController
.. (내용 생략) ..
def recovery
@post = Post.with_deleted.find(params[:id])
@post.restore
redirect_to request.referrer
end
.. (내용 생략) ..
end
3. 라우터에 새로운 URI 규칙을 추가합니다.
get '/posts/recovery/:id' => 'posts#recovery'
4. 끝입니다!
이제 삭제된 게시글에 대해선 '복구' 라는 버튼이 보이고, 해당 버튼을 클릭하면 게시글 내용 자체도 복구가 됩니다.
- 아예 테이블에서 데이터 삭제
만약에 데이터가 보존되지 않고, 아예 삭제를 원하면 다음 메소드를 참고하면 됩니다.
Similarly, when we call really_destroy! on the parent client, then each child email will also have really_destroy! called:
>> client.emails.count
# => 5
>> client.id
# => 12345
>> client.really_destroy!
# => client
>> Client.find 12345
# => ActiveRecord::RecordNotFound
>> Email.with_deleted.where(client_id: client.id).count
# => 0
위 설명을 토대로 한번 구현해보겠습니다.
1. 목록 view에서 다음과 같이 내용을 수정합니다.
## app/views/posts/index.html.erb
<%= link_to '완전 삭제', "/posts/real_destroy/#{post.id}" %>
## app/views/posts/index.html.erb
## 적용 예시
<% @posts.with_deleted.each do |post| %>
<tr>
... (내용 생략) ...
<td><%= link_to '완전 삭제', "posts/real_destroy/#{post.id}" %></td>
</tr>
<% end %>
2. Posts Controllers에 다음 액션을 추가합니다.
## app/controllers/posts_controller.rb
class PostsController < ApplicationController
.. (내용 생략) ..
def real_destroy
@post = Post.with_deleted.find(params[:id])
@post.really_destroy!
redirect_to request.referrer
end
.. (내용 생략) ..
end
3. 라우터에 새로운 URI 규칙을 추가합니다.
get '/posts/real_destroy/:id' => 'posts#real_destroy'
4. 끝입니다!
이제 삭제된 게시글에 대해선 '완전삭제' 라는 버튼이 보입니다.
해당 버튼을 클릭하면 이제는 deleted_at에 남지 않고, really_destroy! 메소드에 의해 아예 데이터가 삭제 됩니다.
- 그 외 다양한 기능
이 외에도 paranoia에서는 다양한 메소드를 지원합니다.
자세한 안내는 Github 문서를 참고해주세요.
※ Github Document : https://github.com/rubysherpas/paranoia
- 자료 참고
1. Paranoia Github Document [클릭]
루비온 레일즈 Ruby on Rails ROR
'프로그래밍 공부 > Ruby on Rails : Gem' 카테고리의 다른 글
Ruby on Rails : 페이지(paginate) [Gem : kaminari] (0) | 2019.11.05 |
---|---|
Ruby on Rails : Devise 로그인 Form 변경하기 (0) | 2019.11.05 |
Ruby on Rails : 조회수 구현 [Gem : impressionist] (0) | 2019.11.05 |
Ruby on Rails : DB 구조를 한눈에 [Gem : rails_db] (0) | 2019.11.05 |
Ruby on Rails : 구글 연동 로그인 API [Gem : omniauth-google-oauth2] (2) | 2019.11.04 |