皆さんは、定数ってよく使いますか?
「Rails」も別の言語と同様で、
どこか専用の場所に定義して使うんだろうなー...ってフワッとした認識だったのですが、調べてみると色々注意点が出てきました。
Railsの定数っていうのは「定数=定まった変数」と言いながら、
実はプログラム内で値を書き換えることが可能なのですね。
チーム開発においては、その辺特にバグの原因にもなり得る箇所かなーなんて思うので、
ぜひ皆さんの今後の開発トラブル回避に繋がるなら幸いだなーと思います!
注意点の前に、
まず、Railsの定数の定義方法について3つ共有します!
定数を定義する方法①【カンタン】
一番カンタンな方法がこちら。
「config/initializers/constants.rb」ファイルに定数を定義する方法です。これが、アプリケーションのどこからでも定数を呼び出せる一番カンタンな方法でした。
module Hoge
FUGA = ["これは定数です"]
end
p Hoge::FUGA
# => "これは定数です"
基本的に大文字で記述します。
今回、目的ごとに定数を分けたかったので、module内に記述しておりますが、
直接定義しても良いと思います↓
ただ、私個人的には後から紹介する「freeze」というメソッドを便利に使うためにも
「module」単位で定義した方が良いかな、とは思いました。
FUGA = ["これは定数です"]
p FUGA
# => "これは定数です"
定数を定義する方法②:環境設定に追記
続いては、アプリケーションの初期設定用のファイルに追記する方法です。
module Hoge
class Application < Rails::Application
config.time_zone = 'Tokyo'
config.i18n.default_locale = :ja
# 追記する
config.x.fuga = ["これは定数です"]
config.x.y.fuga = ["これは2つ目の定数です"]
end
end
p Rails.configuration.x.fuga
# => "これは定数です"
p Rails.configuration.x.y.fuga
# => "これは2つ目の定数です"
ただ、このファイルは滅多に変わらないような初期設定などを記述するような箇所なので、後から変更があり得るような定数を記述するのは、あまり良い方法ではないかなと私は個人的に思いました。
定数を定義する方法③:ymlに追記
ymlファイルに定義する方法は、若干ハードルが高いのですが、なぜおすすめなのかというと、環境ごとの定数を定義できるからです。つまりは「本番環境」「dev環境」「テスト環境」など、環境に応じて複数の定数が定義できるのです。なんとも便利ですよね。
defaults: &defaults
hoge: 200
fuga: "これは定数です"
development:
<<: *defaults
hoge: 100
test:
<<: *defaults
production:
<<: *defaults
定数定義の注意点
続いて、定数定義の注意点についてまとめてみました。実は、上記で紹介したような記述方法だと定数がプログラム内で書き換えられてしまう場合があるのです。
module Hoge
FUGA = ["これは定数です"]
end
p Hoge::FUGA
# => "これは定数です"
# 書き換えてみる
Hoge::FUGA = ["書き換えたよ!!!!"]
warning: already initialized constant Hoge::FUGA
p Hoge::FUGA
# => "書き換えたよ!!!!"
上記のようにプログラム内で、定数を書き換えられてしまう場合があるのです。
特にチーム開発となると、全員が全ての定数を把握するのが難しいですし、
どうしても自分の手元ではうまく動作したのに、結合すると別の人が定義した定数を書き換えてしまっていた...なんてトラブルも起き得ますよね。
注意しても起きてしまう場合があるのは仕方のないことかもしれません。
でも、できることなら、事前に自分が定義した変数を他の人が書き換えられないよう、
ロックできたらベストだとは思いませんか?
解決)freezeで定数を凍結!
解決方法はこちら、【Rails】定数の定義方法【上書きトラブル注意】freezeにもあるのですが、書き換えたくない定数に「freeze」を使うことで解決できます!
FUGA = ["これは定数です"].freeze
なお、molude単位でロックをかける=つまり書き換えを阻止することも
可能です!