【Rails】定数の定義方法【上書きトラブル注意】freeze

エンジニア|ポートフォリオ
新人

PG内でよく使う設定は「定数」としてまとめたい…

方法と注意点について知りたいな。

今回の記事は上記のような方におすすめ。

今回の記事では、Railsにて定数を定義する方法と、定数で起き得るトラブルについて…Rails初心者でもわかるよう、わかりやすく解説いたします!

Railsで定数を定義する方法は非常にカンタンです。しかし注意点があり、書き方によっては意図せずにプログラム内で中身が書き換えられてしまう場合があるのです。

値が「定まった変数」と書いて「定数」なのに、これでは定数とは言えないですよね…。今回は、書き換わるトラブルを防止するための方法についても解説いたします!

エンジニア|ポートフォリオ
新人

間違っている箇所あったらコメントで教えてね。

本記事の内容

なおこの記事は3分で読める内容です。

rails:定数を定義する方法①【カンタン】

おすすめ度
4.5

定数を定義する方法は、いくつかありますが、一番カンタンな方法がこちら。「config/initializers/constants.rb」ファイルに定数を定義する方法です。これが、アプリケーションのどこからでも定数を呼び出せる一番カンタンな方法でしょう。

module Hoge
  FUGA = ["これは定数です"]
end

p Hoge::FUGA
# => "これは定数です"

rails:定数を定義する方法②:環境設定に追記

おすすめ度
2.5

続いては、アプリケーションの大元の設定ファイルに追記する方法。「config/application.rb」ファイルに定数定義する方法です。アプリケーションのタイムゾーンや言語環境など、環境に関する設定が定義されているファイルとなります。

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つ目の定数です"

ただ、このファイルは滅多に変わらないような初期設定などを記述するような箇所なので、後から変更があり得るような定数を記述するのは、あまり良い方法ではないかも知れません。

rails:定数を定義する方法③:ymlに追記

おすすめ度
3.0

続いては、ymlファイルに追記する方法です。「app/config/application.yml」に定義します。

エンジニア|ポートフォリオ
ベテラン

ちなみに、ymlファイルを使った記述をしたことがない方は、

Gemの「Settingsloginc」を使用するのがおすすめ。

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で定数を凍結!

上記のような定数書き換えを防ぐには、定数にロックをかけてあげれば解決です!

module Hoge
  FUGA = ["これは定数です"]
end

# Hogeモジュール全体を凍結する
Hoge.freeze

p Hoge::FUGA
# => "これは定数です"

# 書き換えてみる
Hoge::FUGA = ["書き換えたよ!!!!"]
# => FrozenError: can't modify frozen Module: Hoge::FUGA

なお、モジュール単位ではなく、定数単位でロックをかけることも可能だ。

FUGA = ["これは定数です"].freeze

ただ複数定数を定義したい場合は、module単位でまとめて、その定数モジュール全体にロックをかける方法が一番カンタンだとは思う。

まとめ

他の言語で定数を扱ったことがある場合は、「定数=不変の変数」なんて認識も持つ方も多いかもしれないが、Railsに関して言えば、思わぬ落とし穴になりそう。

複数人開発の際は、こういう細かな部分にも気を配れるようになれると理想だなとは思う。

エンジニア|ポートフォリオ
新人

意外とカンタンだった!

参考

この記事を書いた人

竹田奈央

東京都港区勤務 / 国立大中退 / フルリモートの女性WEBエンジニア / アラサー / 独身 / 基本は石川県にいながら、都内の会社にてフルリモート勤務 / 7月〜東京・軽井沢・千葉 ADDress ワーケーション 中 / 松本人志・千鳥好き / 3日に1回ウンコツイート(←大事) / Twitterは @takeda_no_nao