Soft Delete

Soft Delete

저자가 잘 알고 지내는 IT 개발업체 대표가 있다. 그는 항상 애플리케이션과 데이터 중에서 둘 다 중요하지만, 특히 데이터는 한번 삭제되면 복구할 수 없고 실수로 삭제할 경우는 더욱 난감해 지기 때문에 백업의 중요성과 함께 애플리케이션에서의 모든 삭제는 soft delete 하는 것을 원칙으로 한다고 늘 말한다.

저자도 2년전에 작은 웹애플리케이션을 개발하여 관리하던 중 실수로 데이터베이스의 특정 테이블 데이터를 삭제한 것은 뒤늦게 알게 되어 곤욕을 치른 적이 있다.

저자가 생각하는 soft delete는 애플리케이션에서 행하는 모든 삭제는 데이터베이스에 delete 커밋(hard delete)하지 않고 삭제표시를 위한 플래그 속성을 추가해서 표시하므로써 select 문에서 삭제표시된 레코드를 제외하여 보여주는 것으로 대신하는 것이다.

이와 같이 soft delete는 hard delete에 비해 복구가 가능하다는 장점이 있다. 그리고 일정 기간을 정해 두고 삭제표시된 레코드를 시스템의 스케쥴링 작업을 통해서 데이터베이스로부터 일괄적으로 제거하면 된다.

이와 같은 soft delete는 데이터베이스와 연동해서 프로그래밍할 때는 매우 중요한 의미를 가진다. 레일스를 이용하여 웹애플리케이션을 개발할 때도 마찬가지인데, 어제 저자는 트위터에 올라온 acts_as_paranoid 라는 젬을 알게 되었다.

Gem

사용법은 간단하다.

먼저 Gem을 설치한다. Gemfile을 열고 아래와 같이 추가하고,

gem 'acts_as_paranoid`

번들 인스톨한다.

$ bundle install

Post 모델을 예를 들면 모델 클래스에 acts_as_paranoid 한 줄을 추가해 주면 된다.

class Post < ActiveRecord::Base
  acts_as_paranoid
  
end

그리고 여느 때와 같이 destroy 메소드로 특정 액티브레코드 객체를 삭제하면 된다.

def destroy
  @post = Post.find(params[:id])
  @post.destroy
  redirecto_to posts_path, notice: ‘Successfully deleted.’
end

설명을 위해서 Post 모델을 아래와 같이 scaffolding 한다.

$ rails g scaffold Post title:string content:text deleted_at:datetime

이제 db:migrate 명령을 실행한 후 레일스 콘솔을 실행한다.

$ rails console

아래와 같이 콘솔 내에서 Post 클래스 객체를 생성하고 삭제한 후 복구하는 일련의 작업을 테스트해 본다.

Running via Spring preloader in process 79547
Loading development environment (Rails 5.0.0.1)
>> post = Post.create! title: "post1", content: "content1"
   (0.1ms)  begin transaction
  SQL (0.3ms)  INSERT INTO "posts" ("title", "content", "created_at", "updated_at") VALUES (?, ?, ?, ?)  [["title", "post1"], ["content", "content1"], ["created_at", 2016-08-12 06:33:29 UTC], ["updated_at", 2016-08-12 06:33:29 UTC]]
   (0.6ms)  commit transaction
=> #<Post id: 1, title: "post1", content: "content1", deleted_at: nil, created_at: "2016-08-12 06:33:29", updated_at: "2016-08-12 06:33:29">
>> post.destroy
   (0.1ms)  begin transaction
  SQL (0.3ms)  UPDATE "posts" SET deleted_at = '2016-08-12 06:33:41.977046' WHERE "posts"."deleted_at" IS NULL AND "posts"."id" = ?  [["id", 1]]
   (0.9ms)  commit transaction
=> #<Post id: 1, title: "post1", content: "content1", deleted_at: "2016-08-12 06:33:41", created_at: "2016-08-12 06:33:29", updated_at: "2016-08-12 06:33:29">
>> Post.all
  Post Load (0.3ms)  SELECT "posts".* FROM "posts" WHERE "posts"."deleted_at" IS NULL
=> #<ActiveRecord::Relation []>
>> Post.only_deleted
  Post Load (0.1ms)  SELECT "posts".* FROM "posts" WHERE ("posts"."deleted_at" IS NOT NULL)
=> #<ActiveRecord::Relation [#<Post id: 1, title: "post1", content: "content1", deleted_at: "2016-08-12 06:33:41", created_at: "2016-08-12 06:33:29", updated_at: "2016-08-12 06:33:29">]>
>> Post.only_deleted.first.recover
  Post Load (0.2ms)  SELECT  "posts".* FROM "posts" WHERE ("posts"."deleted_at" IS NOT NULL) ORDER BY "posts"."id" ASC LIMIT ?  [["LIMIT", 1]]
   (0.1ms)  begin transaction
  SQL (0.3ms)  UPDATE "posts" SET "deleted_at" = ?, "updated_at" = ? WHERE "posts"."id" = ?  [["deleted_at", nil], ["updated_at", 2016-08-12 06:34:42 UTC], ["id", 1]]
   (0.7ms)  commit transaction
=> true
>> Post.all
  Post Load (0.1ms)  SELECT "posts".* FROM "posts" WHERE "posts"."deleted_at" IS NULL
=> #<ActiveRecord::Relation [#<Post id: 1, title: "post1", content: "content1", deleted_at: nil, created_at: "2016-08-12 06:33:29", updated_at: "2016-08-12 06:34:42">]>

자세한 내용은 공식문서를 참고하기 바란다.

더욱 강력해진 Turbolinks 3

더욱 강력해진 Turbolinks 3

곧 정식으로 릴리스될 예정인 레일스 5의 여러가지 추가 기능 중에 두 가지가 주목을 받고 있다. 하나는 'ActionCable', 다른 하나는 'Turbolinks 3'다.
'ActionCable'에 대해서는 별도의 글을 준비 중이며, 여기서는 'Turbolinks 3'에 대해서 추가된 기능 중심으로 알아 보도록 하겠다.

참고동영상: New Turbolinks 3 Features With Ruby on Rails

특히 'Turbolinks 3'에서 추가된 기능 중 'Partial Replacement'에 대한 내용을 샘플 애플리케이션과 함께 알아 보도록 하자.
Read more

fields_for 사용기 2016년 업데이트

fields_for 사용기 2016년 업데이트

2012년 04월 14일 “fields_for 사용기”란 제목의 블로그 글을 작성한 적이 있다. 무려 4년전의 일이다.

세월이 많이 흘렀다. 레일스는 최근에 5.0.0.beta1 버전을 릴리스했고 현재 루비의 최신 버전은 2.3.0 이다.

이 글은 이전 글에 대한 2016년도 업데이트라고 생각하면 된다. Read more

Bootstrap용 WYSIWYG 웹에디터 Summernote 사용시 서버로 로컬 이미지 업로드후 삽입하기 (2)

Bootstrap용 WYSIWYG 웹에디터 Summernote 사용시 서버로 로컬 이미지 업로드후 삽입하기 (2)

최근에 summernote0.7.1 버전으로 업그레이드되면서 summernote-rails 젬도 0.7.1.0 버전으로 업데이트되었다.

예전에 Bootstrap용 WYSIWYG 웹에디터 Summernote 사용시 서버로 로컬 이미지 업로드후 삽입하기 (1)라는 제목의 글을 블로그에 올린 바 있다.

summernote-rails 젬이 0.7.1.0으로 버전업되면서 기능추가 및 업데이트가 있어서 이 글에서는 이전 글에서 업데이트된 내용을 소개한다. Read more

터보링크(Turbolinks) 이해하기

터보링크(Turbolinks) 이해하기

동작기전

레일스 애플리케이션의 응답 속도를 높이기 위한 노력의 일환으로 등장한 것이 바로 터보링크(Turbolinks)다. 터보링크는 이름에서도 짐작할 수 있듯이 웹페이지에 있는 링크를 클릭했을 때 현재 페이지를 유지한 채, 브라우저에서 전체 웹페이지를 재컴파일하지 않고 BODY 태그와 헤드 부분의 ‘TITLE’ 값만 불러오도록 함으로써 전체적인 응답속도를 향상시키도록 한다. Read more

중첩 레이아웃을 이용한 레이아웃의 구조화

중첩 레이아웃을 이용한 레이아웃의 구조화

레일스 프레임워크는 애플리케이션 레이아웃를 효율적으로 지원한다.
레일스 프레임워크의 디폴트 레이아웃 파일은 app/views/layouts/application.html.erb이다.

레일스 프로젝트를 생성한 직후 디폴트 레이아웃은 아래와 같다. Read more

댓글전용서비스 플랫폼 Disqus를 레일스 프로젝트에 적용하기

댓글전용서비스 플랫폼 Disqus를 레일스 프로젝트에 적용하기

레일스 프로젝트를 만들 때 글에 대한 댓글을 작성하도록 하면 독자들의 의견을 여러사람들과 공유할 수 있어 좋다.

레일스에서는 이러한 댓글 기능을 너무도 쉽게 구현할 수 있다.

최근에는 이러한 웹서비스의 댓글기능에 많은 부가기능을 지원하여 독자들의 의견을 보다 효율적으로 관리하는 무료 댓글전용 웹서비스에 대한 인기가 놓아지고 있다.

그 중에서도 단연코 넘버 원으로 들 수 있는 것이 Disqus.com이다. 밝음은 `디스커스`라고 하면 된다.

문서화가 잘 되어 있고 사용하기 쉬워 레일스 프로젝트에 적용하기도 쉽다. Read more