Paket ini berisi AASM, perpustakaan untuk menambahkan mesin negara yang terbatas ke kelas Ruby.
AASM dimulai sebagai plugin ACTS_AS_STATE_MACHINE tetapi telah berevolusi menjadi perpustakaan yang lebih umum yang tidak lagi menargetkan hanya model Activerecord. Saat ini menyediakan adaptor untuk banyak ORM tetapi dapat digunakan untuk kelas ruby apa pun, tidak peduli kelas induk apa pun yang dimilikinya (jika ada).
Lihatlah readme_from_version_3_to_4 untuk detail cara beralih dari versi 3.x ke 4.0 dari AASM .
Menambahkan mesin status sesederhana termasuk modul AASM dan mulai mendefinisikan keadaan dan peristiwa bersama dengan transisi mereka:
class Job
include AASM
aasm do
state :sleeping , initial : true
state :running , :cleaning
event :run do
transitions from : :sleeping , to : :running
end
event :clean do
transitions from : :running , to : :cleaning
end
event :sleep do
transitions from : [ :running , :cleaning ] , to : :sleeping
end
end
end Ini memberi Anda beberapa metode publik untuk contoh Job kelas:
job = Job . new
job . sleeping? # => true
job . may_run? # => true
job . run
job . running? # => true
job . sleeping? # => false
job . may_run? # => false
job . run # => raises AASM::InvalidTransition Jika Anda tidak menyukai pengecualian dan lebih suka respons true atau false , beri tahu AASM untuk tidak cengeng :
class Job
...
aasm whiny_transitions : false do
...
end
end
job . running? # => true
job . may_run? # => false
job . run # => falseSaat menembakkan suatu acara, Anda dapat melewati blok ke metode ini, itu akan dipanggil hanya jika transisi berhasil:
job . run do
job . user . notify_job_ran # Will be called if job.may_run? is true
endAnda dapat menentukan sejumlah panggilan balik untuk acara, transisi, dan negara Anda. Metode, procs atau kelas ini akan dipanggil ketika kriteria tertentu dipenuhi, seperti memasuki keadaan tertentu:
class Job
include AASM
aasm do
state :sleeping , initial : true , before_enter : :do_something
state :running , before_enter : Proc . new { do_something && notify_somebody }
state :finished
after_all_transitions :log_status_change
event :run , after : :notify_somebody do
before do
log ( 'Preparing to run' )
end
transitions from : :sleeping , to : :running , after : Proc . new { |* args | set_process ( * args ) }
transitions from : :running , to : :finished , after : LogRunTime
end
event :sleep do
after do
...
end
error do | e |
...
end
transitions from : :running , to : :sleeping
end
end
def log_status_change
puts "changing from #{ aasm . from_state } to #{ aasm . to_state } (event: #{ aasm . current_event } )"
end
def set_process ( name )
...
end
def do_something
...
end
def notify_somebody
...
end
end
class LogRunTime
def call
log "Job was running for X seconds"
end
end Dalam hal ini do_something dipanggil sebelum benar -benar memasuki keadaan sleeping , sementara notify_somebody dipanggil setelah run transisi (dari sleeping ke running ) selesai.
AASM juga akan menginisialisasi LogRunTime dan menjalankan metode call untuk Anda setelah transisi dari running ke finished dalam contoh di atas. Anda dapat meneruskan argumen ke kelas dengan mendefinisikan metode inisialisasi di atasnya, seperti ini:
Perhatikan bahwa Procs dieksekusi dalam konteks catatan, itu berarti bahwa Anda tidak perlu mengharapkan catatan sebagai argumen, panggil saja metode yang Anda butuhkan.
class LogRunTime
# optional args parameter can be omitted, but if you define initialize
# you must accept the model instance as the first parameter to it.
def initialize ( job , args = { } )
@job = job
end
def call
log "Job was running for #{ @job . run_time } seconds"
end
end Anda dapat meneruskan parameter ke acara:
job = Job . new
job . run ( :defragmentation ) Semua penjaga dan setelah panggilan balik akan menerima parameter ini. Dalam hal ini set_process akan dipanggil dengan :defragmentation .
Jika argumen pertama untuk acara tersebut adalah negara bagian (misalnya :running atau :finished ), argumen pertama dikonsumsi dan mesin negara akan berusaha untuk beralih ke negara bagian itu. Tambahkan parameter terpisah koma untuk penjaga dan panggilan balik
job = Job . new
job . run ( :running , :defragmentation ) Dalam hal ini set_process tidak akan dipanggil, pekerjaan akan bertransisi ke status berjalan dan callback akan menerima :defragmentation sebagai parameter
Dalam hal kesalahan selama pemrosesan peristiwa, kesalahan diselamatkan dan diteruskan ke :error , yang dapat menanganinya atau meningkatkannya kembali untuk penyebaran lebih lanjut.
Anda juga dapat mendefinisikan metode yang akan dipanggil jika ada peristiwa yang gagal:
def aasm_event_failed ( event_name , old_state_name )
# use custom exception/messages, report metrics, etc
end Selama transisi :after panggilan balik (dan hanya andal saat itu, atau dalam callback after_all_transitions global) Anda dapat mengakses status asal (dari negara-negara) dan status target (untuk menyatakan), seperti ini:
def set_process ( name )
logger . info "from #{ aasm . from_state } to #{ aasm . to_state } "
end Di sini Anda dapat melihat daftar semua panggilan balik yang mungkin, bersama dengan perintah panggilan mereka:
begin
event before_all_events
event before
event guards
transition guards
old_state before_exit
old_state exit
after_all_transitions
transition after
new_state before_enter
new_state enter
... update state ...
event before_success # if persist successful
transition success # if persist successful, database update not guaranteed
event success # if persist successful, database update not guaranteed
old_state after_exit
new_state after_enter
event after
event after_all_events
rescue
event error
event error_on_all_events
ensure
event ensure
event ensure_on_all_events
end Gunakan callback after_commit dari acara jika harus dipecat setelah pembaruan database.
Saat menjalankan panggilan balik, Anda dapat dengan mudah mengambil nama acara yang dipicu dengan menggunakan aasm.current_event :
# taken the example callback from above
def do_something
puts "triggered #{ aasm . current_event } "
endkemudian
job = Job . new
# without bang
job . sleep # => triggered :sleep
# with bang
job . sleep! # => triggered :sleep! Mari kita asumsikan Anda ingin mengizinkan transisi tertentu hanya jika kondisi yang ditentukan diberikan. Untuk ini Anda dapat mengatur penjaga per transisi, yang akan berjalan sebelum benar -benar menjalankan transisi. Jika penjaga mengembalikan false transisi akan ditolak (meningkatkan AASM::InvalidTransition ):
class Cleaner
include AASM
aasm do
state :idle , initial : true
state :cleaning
event :clean do
transitions from : :idle , to : :cleaning , guard : :cleaning_needed?
end
event :clean_if_needed do
transitions from : :idle , to : :cleaning do
guard do
cleaning_needed?
end
end
transitions from : :idle , to : :idle
end
event :clean_if_dirty do
transitions from : :idle , to : :cleaning , guard : :if_dirty?
end
end
def cleaning_needed?
false
end
def if_dirty? ( status )
status == :dirty
end
end
job = Cleaner . new
job . may_clean? # => false
job . clean # => raises AASM::InvalidTransition
job . may_clean_if_needed? # => true
job . clean_if_needed! # idle
job . clean_if_dirty ( :clean ) # => raises AASM::InvalidTransition
job . clean_if_dirty ( :dirty ) # => trueAnda bahkan dapat menyediakan sejumlah penjaga, yang semuanya harus berhasil melanjutkan
def walked_the_dog? ; ... ; end
event :sleep do
transitions from : :running , to : :sleeping , guards : [ :cleaning_needed? , :walked_the_dog? ]
endJika Anda ingin memberikan penjaga untuk semua transisi dalam suatu acara, Anda dapat menggunakan penjaga acara
event :sleep , guards : [ :walked_the_dog? ] do
transitions from : :running , to : :sleeping , guards : [ :cleaning_needed? ]
transitions from : :cleaning , to : :sleeping
end Jika Anda lebih suka sintaks penjaga seperti ruby, Anda dapat menggunakan if dan unless juga:
event :clean do
transitions from : :running , to : :cleaning , if : :cleaning_needed?
end
event :sleep do
transitions from : :running , to : :sleeping , unless : :cleaning_needed?
end
end Anda dapat memohon kelas alih -alih metode jika kelas merespons untuk call
event :sleep do
transitions from : :running , to : :sleeping , guards : Dog
end class Dog
def call
cleaning_needed? && walked?
end
...
endDalam hal memiliki beberapa transisi untuk suatu acara, transisi pertama yang berhasil diselesaikan akan menghentikan transisi lain dalam acara yang sama dari diproses.
require 'aasm'
class Job
include AASM
aasm do
state :stage1 , initial : true
state :stage2
state :stage3
state :completed
event :stage1_completed do
transitions from : :stage1 , to : :stage3 , guard : :stage2_completed?
transitions from : :stage1 , to : :stage2
end
end
def stage2_completed?
true
end
end
job = Job . new
job . stage1_completed
job . aasm . current_state # stage3 Anda dapat mendefinisikan transisi dari keadaan tertentu dengan menghilangkan from :
event :abort do
transitions to : :aborted
endAnda dapat mendefinisikan nama tampilan untuk status menggunakan: opsi tampilan
class Job
include AASM
aasm do
state :stage1 , initial : true , display : 'First Stage'
state :stage2
state :stage3
end
end
job = Job . new
job . aasm . human_state Beberapa mesin negara per kelas didukung. Waspadai bahwa AASM telah dibangun dengan satu mesin negara per kelas dalam pikiran. Meskipun demikian, inilah cara melakukannya (lihat di bawah). Harap dicatat bahwa Anda perlu menentukan kolom basis data di mana status terkait Anda akan disimpan - kami telah menentukan dua kolom move_state dan work_state dalam contoh di bawah ini. Lihat bagian nama kolom & migrasi untuk info lebih lanjut.
class SimpleMultipleExample
include AASM
aasm ( :move , column : 'move_state' ) do
state :standing , initial : true
state :walking
state :running
event :walk do
transitions from : :standing , to : :walking
end
event :run do
transitions from : [ :standing , :walking ] , to : :running
end
event :hold do
transitions from : [ :walking , :running ] , to : :standing
end
end
aasm ( :work , column : 'work_state' ) do
state :sleeping , initial : true
state :processing
event :start do
transitions from : :sleeping , to : :processing
end
event :stop do
transitions from : :processing , to : :sleeping
end
end
end
simple = SimpleMultipleExample . new
simple . aasm ( :move ) . current_state
# => :standing
simple . aasm ( :work ) . current_state
# => :sleeping
simple . start
simple . aasm ( :move ) . current_state
# => :standing
simple . aasm ( :work ) . current_state
# => :processing AASM tidak melarang untuk mendefinisikan peristiwa yang sama di lebih dari satu mesin negara. Jika tidak ada namespace yang disediakan, definisi terbaru "menang" dan mengesampingkan definisi sebelumnya. Meskipun demikian, peringatan dikeluarkan: SimpleMultipleExample: overriding method 'run'! .
Atau, Anda dapat menyediakan namespace untuk setiap mesin negara bagian:
class NamespacedMultipleExample
include AASM
aasm ( :status ) do
state :unapproved , initial : true
state :approved
event :approve do
transitions from : :unapproved , to : :approved
end
event :unapprove do
transitions from : :approved , to : :unapproved
end
end
aasm ( :review_status , namespace : :review ) do
state :unapproved , initial : true
state :approved
event :approve do
transitions from : :unapproved , to : :approved
end
event :unapprove do
transitions from : :approved , to : :unapproved
end
end
end
namespaced = NamespacedMultipleExample . new
namespaced . aasm ( :status ) . current_state
# => :unapproved
namespaced . aasm ( :review_status ) . current_state
# => :unapproved
namespaced . approve_review
namespaced . aasm ( :review_status ) . current_state
# => :approved Semua metode AASM AASM AASM dan aasm menerima pemilih mesin negara. Jadi, misalnya, untuk menggunakan inspeksi pada tingkat kelas, Anda harus menggunakan
SimpleMultipleExample . aasm ( :move ) . states . map ( & :name )
# => [:standing, :walking, :running]Izinkan acara terikat ke yang lain
class Example
include AASM
aasm ( :work ) do
state :sleeping , initial : true
state :processing
event :start do
transitions from : :sleeping , to : :processing
end
event :stop do
transitions from : :processing , to : :sleeping
end
end
aasm ( :question ) do
state :answered , initial : true
state :asked
event :ask , binding_event : :start do
transitions from : :answered , to : :asked
end
event :answer , binding_event : :stop do
transitions from : :asked , to : :answered
end
end
end
example = Example . new
example . aasm ( :work ) . current_state #=> :sleeping
example . aasm ( :question ) . current_state #=> :answered
example . ask
example . aasm ( :work ) . current_state #=> :processing
example . aasm ( :question ) . current_state #=> :askedAASM secara otomatis menghasilkan konstanta untuk setiap status sehingga Anda tidak perlu secara eksplisit mendefinisikannya.
class Foo
include AASM
aasm do
state :initialized
state :calculated
state :finalized
end
end
> Foo :: STATE_INITIALIZED
#=> :initialized
> Foo :: STATE_CALCULATED
#=> :calculated AASM memungkinkan Anda untuk dengan mudah memperluas AASM::Base untuk tujuan aplikasi Anda sendiri.
Misalkan kita memiliki logika umum di banyak model AASM. Kita dapat mewujudkan logika ini dalam sub-kelas AASM::Base .
class CustomAASMBase < AASM :: Base
# A custom transition that we want available across many AASM models.
def count_transitions!
klass . class_eval do
aasm with_klass : CustomAASMBase do
after_all_transitions :increment_transition_count
end
end
end
# A custom annotation that we want available across many AASM models.
def requires_guards!
klass . class_eval do
attr_reader :authorizable_called ,
:transition_count ,
:fillable_called
def authorizable?
@authorizable_called = true
end
def fillable?
@fillable_called = true
end
def increment_transition_count
@transition_count ||= 0
@transition_count += 1
end
end
end
end Ketika kami mendeklarasikan model kami yang memiliki mesin AASM State, kami hanya mendeklarasikan blok AASM dengan :with_klass kunci dengan kelas kami sendiri.
class SimpleCustomExample
include AASM
# Let's build an AASM state machine with our custom class.
aasm with_klass : CustomAASMBase do
requires_guards!
count_transitions!
state :initialised , initial : true
state :filled_out
state :authorised
event :fill_out do
transitions from : :initialised , to : :filled_out , guard : :fillable?
end
event :authorise do
transitions from : :filled_out , to : :authorised , guard : :authorizable?
end
end
endAASM hadir dengan dukungan untuk ActiveSecord dan memungkinkan status objek yang bertahan secara otomatis dalam database.
Tambahkan gem 'after_commit_everywhere', '~> 1.0' ke permata Anda.
class Job < ActiveRecord :: Base
include AASM
aasm do # default column: aasm_state
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
event :sleep do
transitions from : :running , to : :sleeping
end
end
endAnda dapat memberi tahu AASM untuk menampung objek secara otomatis atau membiarkannya tidak disimpan
job = Job . new
job . run # not saved
job . run! # saved
# or
job . aasm . fire ( :run ) # not saved
job . aasm . fire! ( :run ) # saved Menyimpan termasuk menjalankan semua validasi di kelas Job . Jika bendera whiny_persistence diatur ke true , pengecualian dinaikkan jika terjadi kegagalan. Jika whiny_persistence bendera diatur ke false , metode dengan bang return true jika transisi keadaan berhasil atau false jika kesalahan terjadi.
Jika Anda ingin memastikan negara disimpan tanpa menjalankan validasi (dan dengan demikian mungkin bertahan dalam keadaan objek yang tidak valid), cukup beri tahu AASM untuk melewatkan validasi. Ketahuilah bahwa ketika melewatkan validasi, hanya kolom negara yang akan diperbarui dalam database (seperti ActiveSecord update_column yang berfungsi).
class Job < ActiveRecord :: Base
include AASM
aasm skip_validation_on_save : true do
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
event :sleep do
transitions from : :running , to : :sleeping
end
end
end Anda juga dapat melewatkan validasi pada level instan dengan some_event_name_without_validation! metode. Dengan ini Anda memiliki fleksibilitas memiliki validasi untuk semua transisi Anda secara default dan kemudian lewati di mana pun diperlukan. Harap dicatat bahwa hanya kolom negara yang akan diperbarui seperti yang disebutkan dalam contoh di atas.
job . run_without_validation!Jika Anda ingin memastikan bahwa kolom AASM untuk menyimpan status tidak ditetapkan secara langsung, konfigurasikan AASM untuk tidak mengizinkan penugasan langsung, seperti ini:
class Job < ActiveRecord :: Base
include AASM
aasm no_direct_assignment : true do
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
end
endmengakibatkan ini:
job = Job . create
job . aasm_state # => 'sleeping'
job . aasm_state = :running # => raises AASM::NoDirectAssignmentError
job . aasm_state # => 'sleeping' Anda dapat memberi tahu AASM untuk mencoba menulis cap waktu setiap kali keadaan baru dimasukkan. Jika timestamps: true sudah ditetapkan, AASM akan mencari bidang bernama seperti status baru plus _at dan mencoba mengisinya:
class Job < ActiveRecord :: Base
include AASM
aasm timestamps : true do
state :sleeping , initial : true
state :running
event :run do
transitions from : :sleeping , to : :running
end
end
endmengakibatkan ini:
job = Job . create
job . running_at # => nil
job . run!
job . running_at # => 2020-02-20 20:00:00Bidang cap waktu yang hilang diabaikan secara diam -diam, sehingga tidak perlu memiliki setter (seperti kolom ActiveRecord) untuk semua negara saat menggunakan opsi ini.
Anda dapat menggunakan enumerasi di Rails 4.1+ untuk kolom negara bagian Anda:
class Job < ActiveRecord :: Base
include AASM
enum state : {
sleeping : 5 ,
running : 99
}
aasm column : :state , enum : true do
state :sleeping , initial : true
state :running
end
end Anda dapat secara eksplisit memberikan nama metode yang menyediakan akses ke pemetaan enumerasi sebagai nilai enum , atau Anda dapat mengaturnya ke true . Dalam kasus terakhir AASM akan mencoba menggunakan nama kolom yang pluralisasi untuk mengakses status enum yang mungkin.
Selain itu, jika kolom Anda memiliki tipe integer (yang biasanya terjadi ketika Anda bekerja dengan Rails Enums), Anda dapat menghilangkan :enum --- AASM mendeteksi secara otomatis situasi ini dan mengaktifkan dukungan enum. Jika ada yang salah, Anda dapat menonaktifkan fungsi enum dan kembali ke perilaku default dengan pengaturan :enum ke false .
AASM juga mendukung sekuel selain ActiveSecord , dan Mongoid .
class Job < Sequel :: Model
include AASM
aasm do # default column: aasm_state
...
end
endNamun itu belum selengkap fitur Activerecord . Misalnya, masih ada lingkup yang ditentukan. Lihat lingkup otomatis.
Karena versi 4.8.0 AASM juga mendukung dinamoid sebagai orm persistensi.
AASM juga mendukung kegigihan ke MongoDB jika Anda menggunakan Mongoid. Pastikan untuk memasukkan Mongoid :: Dokumen sebelum Anda memasukkan AASM.
class Job
include Mongoid :: Document
include AASM
field :aasm_state
aasm do
...
end
endAASM juga mendukung kegigihan untuk memikirkan kembali jika Anda menggunakan orang Nobrainer. Pastikan untuk memasukkan nobrainer :: dokumen sebelum Anda memasukkan AASM.
class Job
include NoBrainer :: Document
include AASM
field :aasm_state
aasm do
...
end
endAASM juga mendukung kegigihan di Redis melalui Redis :: Objek. Pastikan untuk memasukkan Redis :: objek sebelum Anda memasukkan AASM. Perhatikan bahwa acara non-bang akan berfungsi sebagai acara Bang, bertahan perubahan pada setiap panggilan.
class User
include Redis :: Objects
include AASM
aasm do
end
endAASM akan secara otomatis membuat metode ruang lingkup untuk setiap keadaan dalam model.
class Job < ActiveRecord :: Base
include AASM
aasm do
state :sleeping , initial : true
state :running
state :cleaning
end
def self . sleeping
"This method name is already in use"
end
end class JobsController < ApplicationController
def index
@running_jobs = Job . running
@recent_cleaning_jobs = Job . cleaning . where ( 'created_at >= ?' , 3 . days . ago )
# @sleeping_jobs = Job.sleeping #=> "This method name is already in use"
end
end Jika Anda tidak memerlukan lingkup (atau hanya tidak menginginkannya), nonaktifkan ciptaan mereka saat mendefinisikan keadaan AASM , seperti ini:
class Job < ActiveRecord :: Base
include AASM
aasm create_scopes : false do
state :sleeping , initial : true
state :running
state :cleaning
end
endKarena versi 3.0.13 AASM mendukung transaksi ActiveRecord. Jadi setiap kali panggilan balik transisi atau pembaruan negara gagal, semua perubahan pada catatan database apa pun digulung kembali. MongoDB tidak mendukung transaksi.
Saat ini ada 3 panggilan balik transaksional yang dapat ditangani pada acara tersebut, dan 2 panggilan balik transaksional untuk semua acara.
event before_all_transactions
event before_transaction
event aasm_fire_event ( within transaction )
event after_commit ( if event successful )
event after_transaction
event after_all_transactions Jika Anda ingin memastikan tindakan tergantung terjadi hanya setelah transaksi dilakukan, gunakan callback after_commit bersama dengan metode Auto-Save (Bang), seperti ini:
class Job < ActiveRecord :: Base
include AASM
aasm do
state :sleeping , initial : true
state :running
event :run , after_commit : :notify_about_running_job do
transitions from : :sleeping , to : :running
end
end
def notify_about_running_job
...
end
end
job = Job . where ( state : 'sleeping' ) . first!
job . run! # Saves the model and triggers the after_commit callback Perhatikan bahwa berikut ini tidak akan menjalankan panggilan balik after_commit karena metode Save Auto tidak digunakan:
job = Job . where ( state : 'sleeping' ) . first!
job . run
job . save! #notify_about_running_job is not run Harap dicatat bahwa :after_commit AASM Callbacks berperilaku di sekitar implementasi kustom dari pola transaksi daripada transaksi DB kehidupan nyata. Fakta ini masih menyebabkan kondisi balapan dan panggilan balik balik yang berlebihan dalam transaksi bersarang. Untuk memperbaikinya, sangat disarankan untuk menambahkan gem 'after_commit_everywhere', '~> 1.0' ke Gemfile Anda.
Jika Anda ingin merangkum perubahan keadaan dalam transaksi sendiri, perilaku transaksi bersarang ini mungkin membingungkan. Lihatlah transaksi bersarang Activerecord jika Anda ingin tahu lebih banyak tentang ini. Namun demikian, AASM secara default membutuhkan transaction(requires_new: true) . Anda dapat mengganti perilaku ini dengan mengubah konfigurasi
class Job < ActiveRecord :: Base
include AASM
aasm requires_new_transaction : false do
...
end
...
end yang kemudian mengarah ke transaction(requires_new: false) , default rel.
Selain itu, jika Anda tidak ingin tindakan Activerecord Anda dibungkus dalam transaksi, Anda dapat menentukan bendera use_transactions . Ini bisa bermanfaat jika Anda ingin bertahan dalam database yang terjadi sebagai akibat dari transaksi atau panggilan balik, bahkan ketika beberapa kesalahan terjadi. Bendera use_transactions benar secara default.
class Job < ActiveRecord :: Base
include AASM
aasm use_transactions : false do
...
end
...
end AASM mendukung penguncian pesimistis Activerecord via with_lock untuk lapisan persistensi basis data.
| Pilihan | Tujuan |
|---|---|
false (default) | Tidak ada kunci yang diperoleh |
true | Dapatkan kunci pesimistis pemblokiran misalnya FOR UPDATE |
| Rangkaian | Dapatkan kunci berdasarkan string SQL EG FOR UPDATE NOWAIT |
class Job < ActiveRecord :: Base
include AASM
aasm requires_lock : true do
...
end
...
end class Job < ActiveRecord :: Base
include AASM
aasm requires_lock : 'FOR UPDATE NOWAIT' do
...
end
...
end Sebagai default AASM menggunakan kolom aasm_state untuk menyimpan status. Anda dapat mengganti ini dengan mendefinisikan nama kolom favorit Anda, menggunakan :column seperti ini:
class Job < ActiveRecord :: Base
include AASM
aasm column : :my_state do
...
end
aasm :another_state_machine , column : :second_state do
...
end
end Apa pun nama kolom yang digunakan, pastikan untuk menambahkan migrasi untuk menyediakan kolom ini (tipe string ). Jangan menambahkan nilai default untuk kolom di level database. Jika Anda menambahkan nilai default dalam database maka callback AASM pada keadaan awal tidak akan ditembakkan pada saat instantiasi model.
class AddJobState < ActiveRecord :: Migration
def self . up
add_column :jobs , :aasm_state , :string
end
def self . down
remove_column :jobs , :aasm_state
end
endPerubahan status logging dapat dilakukan dengan menggunakan permata paper_trail
Contoh implementasi dapat ditemukan di sini https://github.com/nitsujri/aasm-papertrail-example
AASM mendukung metode kueri untuk negara bagian dan acara
Mengingat kelas Job berikut:
class Job
include AASM
aasm do
state :sleeping , initial : true
state :running , :cleaning
event :run do
transitions from : :sleeping , to : :running
end
event :clean do
transitions from : :running , to : :cleaning , guard : :cleaning_needed?
end
event :sleep do
transitions from : [ :running , :cleaning ] , to : :sleeping
end
end
def cleaning_needed?
false
end
end # show all states
Job . aasm . states . map ( & :name )
#=> [:sleeping, :running, :cleaning]
job = Job . new
# show all permitted states (from initial state)
job . aasm . states ( permitted : true ) . map ( & :name )
#=> [:running]
# List all the permitted transitions(event and state pairs) from initial state
job . aasm . permitted_transitions
#=> [{ :event => :run, :state => :running }]
job . run
job . aasm . states ( permitted : true ) . map ( & :name )
#=> [:sleeping]
# show all non permitted states
job . aasm . states ( permitted : false ) . map ( & :name )
#=> [:cleaning]
# show all possible (triggerable) events from the current state
job . aasm . events . map ( & :name )
#=> [:clean, :sleep]
# show all permitted events
job . aasm . events ( permitted : true ) . map ( & :name )
#=> [:sleep]
# show all non permitted events
job . aasm . events ( permitted : false ) . map ( & :name )
#=> [:clean]
# show all possible events except a specific one
job . aasm . events ( reject : :sleep ) . map ( & :name )
#=> [:clean]
# list states for select
Job . aasm . states_for_select
#=> [["Sleeping", "sleeping"], ["Running", "running"], ["Cleaning", "cleaning"]]
# show permitted states with guard parameter
job . aasm . states ( { permitted : true } , guard_parameter ) . map ( & :name ) Peringatan secara default dicetak ke STDERR . Jika Anda ingin mencatat peringatan itu ke output lain, gunakan
class Job
include AASM
aasm logger : Rails . logger do
...
end
end Anda dapat menyembunyikan peringatan dengan mengatur AASM::Configuration.hide_warnings = true
Sekarang mendukung codedataquery! Namun saya masih dalam proses mengirimkan pembaruan kompatibilitas saya ke repositori mereka. Sementara itu, Anda dapat menggunakan garpu saya, mungkin masih ada beberapa masalah kecil tetapi saya bermaksud untuk menggunakannya sendiri secara luas, jadi perbaikan harus datang dengan cepat.
Peringatan:
AASM menyediakan beberapa pencocokan untuk RSPEC:
transition_from ,have_state , allow_eventallow_transition_to . require 'aasm/rspec' ke file spec_helper.rb Anda. # classes with only the default state machine
job = Job . new
expect ( job ) . to transition_from ( :sleeping ) . to ( :running ) . on_event ( :run )
expect ( job ) . not_to transition_from ( :sleeping ) . to ( :cleaning ) . on_event ( :run )
expect ( job ) . to have_state ( :sleeping )
expect ( job ) . not_to have_state ( :running )
expect ( job ) . to allow_event :run
expect ( job ) . to_not allow_event :clean
expect ( job ) . to allow_transition_to ( :running )
expect ( job ) . to_not allow_transition_to ( :cleaning )
# on_event also accept multiple arguments
expect ( job ) . to transition_from ( :sleeping ) . to ( :running ) . on_event ( :run , :defragmentation )
# classes with multiple state machine
multiple = SimpleMultipleExample . new
expect ( multiple ) . to transition_from ( :standing ) . to ( :walking ) . on_event ( :walk ) . on ( :move )
expect ( multiple ) . to_not transition_from ( :standing ) . to ( :running ) . on_event ( :walk ) . on ( :move )
expect ( multiple ) . to have_state ( :standing ) . on ( :move )
expect ( multiple ) . not_to have_state ( :walking ) . on ( :move )
expect ( multiple ) . to allow_event ( :walk ) . on ( :move )
expect ( multiple ) . to_not allow_event ( :hold ) . on ( :move )
expect ( multiple ) . to allow_transition_to ( :walking ) . on ( :move )
expect ( multiple ) . to_not allow_transition_to ( :running ) . on ( :move )
expect ( multiple ) . to transition_from ( :sleeping ) . to ( :processing ) . on_event ( :start ) . on ( :work )
expect ( multiple ) . to_not transition_from ( :sleeping ) . to ( :sleeping ) . on_event ( :start ) . on ( :work )
expect ( multiple ) . to have_state ( :sleeping ) . on ( :work )
expect ( multiple ) . not_to have_state ( :processing ) . on ( :work )
expect ( multiple ) . to allow_event ( :start ) . on ( :move )
expect ( multiple ) . to_not allow_event ( :stop ) . on ( :move )
expect ( multiple ) . to allow_transition_to ( :processing ) . on ( :move )
expect ( multiple ) . to_not allow_transition_to ( :sleeping ) . on ( :move )
# allow_event also accepts arguments
expect ( job ) . to allow_event ( :run ) . with ( :defragmentation ) AASM memberikan pernyataan dan ekspektasi seperti RSPEC untuk Minitest.
Daftar pernyataan yang didukung: assert_have_state , refute_have_state , assert_transitions_from , refute_transitions_from , assert_event_allowed , refute_event_allowed , assert_transition_to_allowed , refute_transition_to_allowed .
Tambahkan require 'aasm/minitest' ke file test_helper.rb Anda dan gunakan seperti ini:
# classes with only the default state machine
job = Job . new
assert_transitions_from job , :sleeping , to : :running , on_event : :run
refute_transitions_from job , :sleeping , to : :cleaning , on_event : :run
assert_have_state job , :sleeping
refute_have_state job , :running
assert_event_allowed job , :run
refute_event_allowed job , :clean
assert_transition_to_allowed job , :running
refute_transition_to_allowed job , :cleaning
# on_event also accept arguments
assert_transitions_from job , :sleeping , :defragmentation , to : :running , on_event : :run
# classes with multiple state machine
multiple = SimpleMultipleExample . new
assert_transitions_from multiple , :standing , to : :walking , on_event : :walk , on : :move
refute_transitions_from multiple , :standing , to : :running , on_event : :walk , on : :move
assert_have_state multiple , :standing , on : :move
refute_have_state multiple , :walking , on : :move
assert_event_allowed multiple , :walk , on : :move
refute_event_allowed multiple , :hold , on : :move
assert_transition_to_allowed multiple , :walking , on : :move
refute_transition_to_allowed multiple , :running , on : :move
assert_transitions_from multiple , :sleeping , to : :processing , on_event : :start , on : :work
refute_transitions_from multiple , :sleeping , to : :sleeping , on_event : :start , on : :work
assert_have_state multiple , :sleeping , on : :work
refute_have_state multiple , :processing , on : :work
assert_event_allowed multiple , :start , on : :move
refute_event_allowed multiple , :stop , on : :move
assert_transition_to_allowed multiple , :processing , on : :move
refute_transition_to_allowed multiple , :sleeping , on : :move Daftar harapan yang didukung: must_transition_from , wont_transition_from , must_have_state , wont_have_state , must_allow_event , wont_allow_event , must_allow_transition_to , wont_allow_transition_to .
Tambahkan require 'aasm/minitest_spec' ke file test_helper.rb Anda dan gunakan seperti ini:
# classes with only the default state machine
job = Job . new
job . must_transition_from :sleeping , to : :running , on_event : :run
job . wont_transition_from :sleeping , to : :cleaning , on_event : :run
job . must_have_state :sleeping
job . wont_have_state :running
job . must_allow_event :run
job . wont_allow_event :clean
job . must_allow_transition_to :running
job . wont_allow_transition_to :cleaning
# on_event also accept arguments
job . must_transition_from :sleeping , :defragmentation , to : :running , on_event : :run
# classes with multiple state machine
multiple = SimpleMultipleExample . new
multiple . must_transition_from :standing , to : :walking , on_event : :walk , on : :move
multiple . wont_transition_from :standing , to : :running , on_event : :walk , on : :move
multiple . must_have_state :standing , on : :move
multiple . wont_have_state :walking , on : :move
multiple . must_allow_event :walk , on : :move
multiple . wont_allow_event :hold , on : :move
multiple . must_allow_transition_to :walking , on : :move
multiple . wont_allow_transition_to :running , on : :move
multiple . must_transition_from :sleeping , to : :processing , on_event : :start , on : :work
multiple . wont_transition_from :sleeping , to : :sleeping , on_event : :start , on : :work
multiple . must_have_state :sleeping , on : :work
multiple . wont_have_state :processing , on : :work
multiple . must_allow_event :start , on : :move
multiple . wont_allow_event :stop , on : :move
multiple . must_allow_transition_to :processing , on : :move
multiple . wont_allow_transition_to :sleeping , on : :move % gem install aasm # Gemfile
gem 'aasm'% rake build
% sudo gem install pkg/aasm-x.y.z.gemSetelah menginstal AASM, Anda dapat menjalankan generator:
% rails generate aasm NAME [COLUMN_NAME]Ganti nama dengan nama model, column_name adalah opsional (default adalah 'aasm_state'). Ini akan membuat model (jika tidak ada) dan mengkonfigurasinya dengan blok AASM. Untuk ActiveRecord ORM file migrasi ditambahkan untuk menambahkan kolom AASM State ke tabel.
Jalankan Test Suite dengan mudah di Docker
1. docker-compose build aasm
2. docker-compose run --rm aasm
Lihatlah changelog untuk detail tentang perubahan terbaru pada versi saat ini.
Jangan ragu
aasm )Perangkat lunak ini disediakan "sebagaimana adanya" dan tanpa jaminan tersurat atau tersirat, termasuk, tanpa batasan, jaminan tersirat dari dapat diperjualbelikan dan kebugaran untuk tujuan tertentu.
Hak Cipta (C) 2006-2017 Scott Barron
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
Pemberitahuan hak cipta di atas dan pemberitahuan izin ini harus dimasukkan dalam semua salinan atau bagian substansial dari perangkat lunak.
Perangkat lunak ini disediakan "sebagaimana adanya", tanpa jaminan apa pun, tersurat maupun tersirat, termasuk tetapi tidak terbatas pada jaminan dapat diperjualbelikan, kebugaran untuk tujuan tertentu dan nonpringement. Dalam hal apa pun penulis atau pemegang hak cipta tidak akan bertanggung jawab atas klaim, kerusakan atau tanggung jawab lainnya, baik dalam tindakan kontrak, gugatan atau sebaliknya, timbul dari, di luar atau sehubungan dengan perangkat lunak atau penggunaan atau transaksi lain dalam perangkat lunak.