システムを構築してると、幾つかのステータスを持つことがあります。例えば、商品についてのモデルProduct
のstatus
として、「発売予定」「発売中」「絶版」「再販未定」の4つのステータスを持っているとします。
これらを扱うModelの良い書き方を紹介します。
目次
それぞれのステータスを10, 20, 30, 40という数値で管理しようと思います。
そのとき単にinteger型のフィールドにすると、例えば、発売中にステータスをフォームは
<%= form_for @product do |f| %>
<%= f.label :status %>
<%= f.radio_button :status, 10 %> 発売予定
<%= f.radio_button :status, 20 %> 発売中
<%= f.radio_button :status, 30 %> 絶版
<%= f.radio_button :status, 40 %> 再販未定
<% end %>
となったり、
def in_sale?
self.status == 20
end
となるなど、ここだけでは意味が分からない数値が入って可読性が悪くなってしまいます。
それを防ぐための機能としてRailsのModelにはEnumという機能が用意されています。
Modelに以下のように書きます。
class Product < ActiveRecord::Base
enum status: {will_be_released: 10 ,in_sale: 20, sold_out: 30, resale_undecided: 40}
end
このように定義してやると、DBの値は10,20,30,40のままで、コード内では:will_be_released
などで参照できます。
たとえば、先ほどのViewのコードは以下のように書くことができます。
<%= form_for @product do |f| %>
<%= f.label :status %>
<%= f.radio_button :status, :will_be_released %> 発売予定
<%= f.radio_button :status, :in_sale %> 発売中
<%= f.radio_button :status, :sold_out %> 絶版
<%= f.radio_button :status, :resale_undecided %> 再販未定
<% end %>
このようにしてやれば、無意味な数値がコードに入らないのでよみやすくなります。
また、ふたつ目のin_sale?
メソッドについてですが、実はeunmを定義した時点で自動的に作成されます。同様にstatus
を:in_sale
に更新するメソッドとしてin_sale!
も作成されています。
また、:will_be_released
, :in_sale
, :sold_out
, :resale_undecided
以外の値を代入すると、エラーが発生するため、DB自体にConstraintを設定することなく、データの整合性も保つことができます。
今回、それぞれの判別用の数字を10, 20, 30, 40としましたが、このように10飛びに、あるいは100飛びにすることによって、間に新しいステータスができたとき、15のように間に値を数値入れることができます。
ただのIDとしての役割しか果たしていないので、もちろん、後ろに50とおいてもいいのですが、なんとなく気持ち悪さがあるので、自分はいつもこのように置いています。
ModelのEnumを使うことで、得られる主なメリットは可読性の工場ですが、様々な便利なメソッドが用意されたり、DBの設定を変更しなくても保存可能な値を増やせたりします。
また、enum_help
というGemを代入することで多言語対応も可能です。
このような保存する値が決まっているものに関しては積極的にEnumを作っていきましょう。