티스토리 뷰

해당 글은 https://blog.naver.com/kbs4674/221052897085 로 부터 게시글이 이전되었습니다.

 

Soft Delete

사이트 운영자는 자신의 홈페이지를 운영하면서 홈페이지 내 데이터가 삭제된다면, 그것이 그냥 삭제되도록 냅두는것이 아닌 삭제된 데이터에 대해 기록이 남겨져야 할 이유가 있습니다.

나중에 게시글 내 욕설로 인해 피해자가 가해자에게 고소를 하면, 게시글을 관리하는 사이트 운영자는 고소의 시발점이 되는 (삭제된) 자료를 경찰이 요구를 하면 해당 게시글의 (삭제된) 기록에 대해 보여줘야 할 의무가 있기 때문입니다.

 

그래서, 이번 시간에는 삭제된 데이터를 보관하는방법에 대해 알아보고자 합니다.

참고로 해당 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

댓글
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2024/04   »
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28 29 30
글 보관함