AASM이란
Rails에서 상태관리 기능을 간단히 만들 수 있는 Gem이다.
예를들면 채팅어플에서 보낸메일을 상대방이 보지 못했을때(읽지않은 상태)와 상대방이 읽었을때(읽음 상태)
등의 상태를 구현가능하다.
이 포스트에서는 게시판형식에서 글을 등록할때 전체공개,그룹공개,비공개의 상태를 가지게 하는 예제를 만들어볼것이다.
AASM에서는 특정상태에 대한 정의는 state
를 사용하고 A상태에서 B상태로 바뀌는 액션을 event
를 사용한다.
예제를 보면 알기 쉬울것이다.
AASM인스톨(Gemfile)
# Gemfile
gem 'aasm'
상태관리용 컬럼추가
rails로 퀴즈어플 만들어보기(CRUD편) 에서 만든 writing_quiz라는 모델에 상태관리용 컬럼을 추가해보자
이하와 같은 커맨드를 실행하면 자동으로 migrate파일이 만들어진다.
default로는 aasm_state라는 컬럼이 만들어진다.
특별한 이유가 없으면 default그대로 쓰는게 좋을 것 같다.
rails generate aasm writing_quiz
result:
invoke active_record
create db/migrate/20180504075459_add_aasm_state_to_writing_quizzes.rb
insert app/models/writing_quiz.rb
db:migrate로 실제 컬럼을 추가시킨다.
rake db :migrate
모델에 설정 추가
aasm_state컬럼을 추가한 모델에 이하 설정을 추가해주자.
#app/models/writing_quiz.rb
class WritingQuiz < ApplicationRecord
include AASM
aasm do
state :draft , :initial => true #default 비공개상태
state :published #전체공개 상태
state :limited_public #제한된 공개상태
#비공개,제한공개상태에서 공개상태로 상태를 전환시키는 event
event :publish do
transitions :from => [ :draft , :limited_public ], :to => :published
end
#전체공개,제한공개상태에서 비공개 상태로 전환시키는 event
event :draft do
transitions :from => [ :limited_public , :published ], :to => :draft
end
#전체공개,비공개상태에서 제한공개 상태로 전환시키는 event
event :limit_publish do
transitions :from => [ :draft , :published ], :to => :limited_public
end
end
end
rails console에서 동작확인
여기까지 설정하면 Rails에서AASM을 사용할 준비가 끝났다.
Rails console에서 동작확인을 해보자.
상태확인방법
wq = WritingQuiz . new
wq . drfat? #현재상태는 비공개 상태입니까?라고 확인하는 커맨드 디폴트값이 draft이므로 true가 반환된다.
=> true
wq . publish? #현재상태는 전체공개가 아니므로 false가 반환된다.
=> false
상태 바꿔보기
wq . publish #디폴트 비공개상태에서 전체공개로 상태를 변경
wq . drfat? #다시 비공개상태냐고 질의하면 현재는 전체공개상태이므로 false가 반환된다.
=> false
wq . limit_publish #전체공개 상테에서 그룹공개 상태 로 변경
wq . draft? #그룹공개 상태이므로 false가 반환
=> false
wq . limit_public #그룹공개상태이므로 true가 반환됨.
=> true
컨트롤러/뷰 설정확인
다음은 Rails컨트롤러와 뷰에서 어떤식으로 사용하는지 살펴보자.
view 설정
< div class = "main posts-new" >
< div class = "container" >
< h1 class = "form-heading" > 수정하기 < /h1>
<%= form_for @wquiz do |w| %>
<div class="form">
<div class="form-body">
<% @wquiz.errors.full_messages.each do |message| %>
<div class="form-error">
<%= message %>
</ div >
< % end %>
< div class = question >
< %= w.label :question, "질문" %>
<%= w . text_field :question %>
< /div>
<div class="answer">
<%= w.label :answer, "정답" %>
<%= w.text_field :answer %>
</ div >
< %= w.button "전체공개 등록", name: 'ope[cmd]', value: 'publish' %>
<%= w . button "그룹공개 등록" , name: 'ope[cmd]' , value: 'limit_publish' %>
< %= w.button "비공개 등록", name: 'ope[cmd]', value: 'draft' %>
</div>
</div>
<% end %>
</div>
</div>
화면캡쳐
submit type의 버튼 3개에 서로다른 value값을 둬서
컨트롤러에서 어떤 버튼을 눌렀는지 판별할 수 있게 해둔것이 특징이다.
컨트롤러 설정
before_action :set_aasm , only: [ :update , :create ]
def set_aasm
case params [ :ope ][ :cmd ]
when 'publish'
flash [ :notice ] = "전체공개 했습니다"
@wquiz . publish! if ! @wquiz . published?
when 'limit_publish'
flash [ :notice ] = "그룹공개 했습니다."
@wquiz . limit_publish! if ! @wquiz . limited_public?
when 'draft'
flash [ :notice ] = "비공개로 등록했습니다."
@wquiz . draft! if ! @wquiz . draft?
else
end
end
컨트롤러에서는 case,when문을 이용해서 어떤 버튼을 눌렀는지에 따라 특정 상태로 변경하고 있다.
그리고 신규등록과 수정 양쪽다 스테터스 변경할 수 있게끔 공통 메소드set_aasm을 만들었다.
모델에 정의한 AASM설정이 다른 스테터스로만의 변경만 가능하게 했으므로
예를들어 전체공개인 상태에서 전체공개로 스테터스를 변환하려 하면 에러가나므로 동일 스테터스일 경우 스킵하도록 했다.
동작확인
위 예제를 참고해서 등록,수정을 한뒤
rails log를 보면 이하와 같이 aasm_state값이 갱신되는걸 알 수 있다.
Parameters: {"utf8"=>"✓", "authenticity_token"=>"qppuaWtSENBYUiUEGEcV9JODxWVCZZUoYbI4HOQjkKNLVWT0IW5m46lISoh5Kd5OSXYPpE6hz/22g8ldbNl0Rw==", "writing_quiz"=>{"question"=>"1+1은?", "answer"=>"귀여미"}, "ope"=>{"cmd"=>"draft"}}
(0.3ms) BEGIN
SQL (13.5ms) INSERT INTO `writing_quizzes` (`question`, `answer`, `created_at`, `updated_at`, `aasm_state`) VALUES ('1+1은?', '귀여미', '2018-05-04 12:34:39', '2018-05-04 12:34:39', 'draft')
(23.7ms) COMMIT