ActiveRecord::Enum 데이터형의 활용

모델의 특정 상태를 저장하고자 할 때 각각의 상태를 정수로 할당한 후 문자열로 매핑하면 매우 편리하다.

이러한 상태 저장방식은 실무에서 많이 사용하는데 레일스 4.1버전부터 도입된 enum형을 사용하면 여러가지로 편리한다.

이글에서는 ActiveRecordenum형을 사용하는 방법에 대해서 알아 보기로 한다.

이해를 돕기 위해서, 논문 정보를 정의하는 Paper라는 모델을 예로 들어 보자.

우선 EnumTest라는 레일스 프로젝트를 생성하다.

$ rails new EnumTest && cd EnumTest
      create
      create  README.rdoc
      create  Rakefile
      create  config.ru
      create  .gitignore
      create  Gemfile
      create  app
      create  app/assets/javascripts/application.js
      create  app/assets/stylesheets/application.css
      create  app/controllers/application_controller.rb
      create  app/helpers/application_helper.rb
      create  app/views/layouts/application.html.erb
      create  app/assets/images/.keep
      create  app/mailers/.keep
      create  app/models/.keep
      create  app/controllers/concerns/.keep
      create  app/models/concerns/.keep
...

이제, 커맨드라인에서 아래와 같이 3개의 속성을 가지는 Paper 모델을 scaffolding 하자.

 
$ rails g scaffold Paper title summary:text status:integer
      invoke  active_record
      create    db/migrate/20150713110048_create_papers.rb
      create    app/models/paper.rb
      invoke    test_unit
      create      test/models/paper_test.rb
      create      test/fixtures/papers.yml
      invoke  resource_route
       route    resources :papers
      invoke  scaffold_controller
      create    app/controllers/papers_controller.rb
      invoke    erb
... 

위에서 생성된 마이그레이션 파일(db/migrate/20150713110048_create_papers.rb)을 에디터로 열고, 아래와 같이 status 속성의 기본값을 0으로 지정한 후 마이그레이션 하자.

 
class CreatePapers < ActiveRecord::Migration
  def change
    create_table :papers do |t|
      t.string :title
      t.text :summary
      t.integer :status, default: 0

      t.timestamps null: false
    end
  end
end

Paper 클래스 파일(app/models/paper.rb)를 에디터로 열고, 아래와 같이 status 속성을 enum형으로 선언한다.

class Paper < ActiveRecord::Base
  enum status: { draft:0, confirmed:1, working:2, published:3 }
  # 또는
  # enum status: %w( draft confirmed working published )
end

다음은, 커맨드라인에서 rails console 명령을 실행한 후 빈 객체를 생성하자.

irb(main)> new_paper = Paper.new
=> <Paper id: nil, title: nil, summary: nil, status: 0, created_at: nil, updated_at: nil>

그리고 status 속성값을 확인해 보자.

irb(main)> new_paper.status
=> "draft"

어떻게 해서 "draft" 값이 반환되는 것일까? 눈치가 빠른 독자는 이미 이해를 했을 것이다.

우리는 위의 마이그레이션 파일에서 status 속성의 디폴트 값을 0으로 지정했었다. 따라서 새로운 레코드가 생성될 때 status의 값은 정수 0을 가지게 되는데, Paper 클래스에서 status 속성을 enum형으로 지정했었다. 한가지 유의해야 할 것은 맨처음 키는 디폴트 값으로 사용할 수 있도록 0 값으로 매핑하는 것이 좋다는 것이다. 여기에서도 맨처럼 값 0에 “draft” 키를 매핑해 놓았다. 따라서 당연히 디폴트 값 0으로 매핑된 “draft” 값이 반환하게 되는 것이다.

enum형으로 선언할 경우 우리는 두가지 이점을 가질 수 있다.

하나는 키에 !를 추가하여 setter메소드로, ?를 추가하여 getter메소드로 사용할 수 있게 된다는 것이다.

위에서 생성한 빈 객체인 new_paperworking!을 호출하면 status 속성에 2값을 할당한 후 저장하게 된다.

irb(main)> new_paper.working!
   (0.2ms)  BEGIN
  SQL (0.2ms)  INSERT INTO `papers` (`status`, `created_at`, `updated_at`) VALUES (2, '2015-07-13 10:04:37', '2015-07-13 10:04:37')
   (0.8ms)  COMMIT
=> true

이제 새로 추가된 paper 객체를 불러와 statusconfirmed 상태로 변경해 보자.

irb(main)> paper = Paper.first
irb(main)> paper.confirmed!
   (0.2ms)  BEGIN
  SQL (0.3ms)  UPDATE `papers` SET `status` = 1, `updated_at` = '2015-07-13 10:38:25' WHERE `papers`.`id` = 1
   (1.1ms)  COMMIT
=> true

다음은 변경된 상태를 확인해 보자.

irb(main)> paper.confirmed?
=> true

true 값이 반환되어 제대로 변경된 것을 확인할 수 있다. 그렇다면 paper.working?와 같이 호출하면 어떤 값이 반환될까 상상해 보자.

irb(main)> paper.working?
=> false

false 값을 예상했다면 지금까지 설명한 내용을 제대로 이해한 것이다.

또 하나의 이점은 키 이름을 해당 모델 클래스의 scope 클래스 메소드로 바로 사용할 수 있게 된다는 것이다. 아래를 보자.

irb(main)> Paper.confirmed
  Paper Load (0.3ms)  SELECT `papers`.* FROM `papers` WHERE `papers`.`status` = 1
=> #<ActiveRecord::Relation [#<Paper id: 1, title: "", summary: "", status: 1, created_at: "2015-07-13 05:15:48", updated_at: "2015-07-13 10:38:25">]>

이것은 Paper.where(status: 1)를 호출할 것과 같은 결과를 보인다. 이것은 아래와 같이 모델 scope를 지정한 경우와도 동일하 결과를 보여 준다.

class Paper < ActiveRecord::Base
  scope :confirmed, -> { where(status: 1) }
end

이번에는 작성 중인 논문들을 불러와 보자.

irb(main)> Paper.working
  Paper Load (0.4ms)  SELECT `papers`.* FROM `papers` WHERE `papers`.`status` = 2
=> #<ActiveRecord::Relation []>

당연한 결과일 것이다. 아직 2번 상태(working)로 지정한 논문은 없기 때문이다.

이상으로 ActiveRecord::Enum 데이터형을 활용해서 모델 상태를 효과적으로 관리하는 방법에 대해서 간단하게 알아 보았다.

글쓴이: 최효성

외과전문의,웹프로그래밍,컴퓨터 일러스트레이션 / Surgeon, Medical Illustration, Web Programmer

답글 남기기

아래 항목을 채우거나 오른쪽 아이콘 중 하나를 클릭하여 로그 인 하세요:

WordPress.com 로고

WordPress.com의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Twitter 사진

Twitter의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Facebook 사진

Facebook의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

Google+ photo

Google+의 계정을 사용하여 댓글을 남깁니다. 로그아웃 / 변경 )

%s에 연결하는 중