LoginSignup
3
1

More than 3 years have passed since last update.

【Rails】定数を定義したらとりあえず freeze しておく

Last updated at Posted at 2021-02-22

はじめに

# 定数を定義した例
ARASHI_MEMBERS = ['大野', '松本', '二宮', '桜井', '相葉'].freeze

上記のように Rails で定義した定数は基本的に freeze しておくのがベストです。

不用意に変更されることを防げます。

freeze しておくと、もし ARASHI_MEMBERS に破壊的な変更が行われようとした時に FrozenError を起こしてくれます。

irb(main):001:0> ARASHI_MEMBERS << '木村'
Traceback (most recent call last):
        4: from /Users/dan/.rbenv/versions/2.7.1/bin/irb:23:in `<main>'
        3: from /Users/dan/.rbenv/versions/2.7.1/bin/irb:23:in `load'
        2: from /Users/dan/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/irb-1.2.3/exe/irb:11:in `<top (required)>'
        1: from (irb):2
FrozenError (can't modify frozen Array: ["大野", "松本", "二宮", "桜井", "相葉"]

なので ARASHI_MEMBERS を呼び出した時はいつでもこの5人であることが保証されます。

応用① freeze した定数を変更して使いたい時

もし ARASHI_MEMBERS を変更して使いたい時は dup メソッドを使いましょう。 freeze されていない コピーを作れます。

irb(main):001:0> tmp_arashi_members = ARASHI_MEMBERS.dup
irb(main):002:0> tmp_arashi_members << '木村'
=> ["大野", "松本", "二宮", "桜井", "相葉", "木村"]

※ ちなみに dup せずに変数に定義して変更を行うとやはり FrozenError が発生します。

応用② ネストされた Array や Hash を freeze したい時

ちなみに上記の freeze メソッドはネストされていると深くまで完全に機能しません。

irb(main):001:0> JOHNNYS_MEMBERS = {arashi: ["大野", "松本", "二宮", "桜井", "相葉"] , kat_tun:['亀梨', '上田', '中丸']}.freeze
irb(main):002:0> JOHNNYS_MEMBERS[:arashi] << ' 木村'
=> ["大野", "松本", "二宮", "桜井", "相葉", " 木村"]
irb(main):003:0> JOHNNYS_MEMBERS
=> {:arashi=>["大野", "松本", "二宮", "桜井", "相葉", " 木村"], :kat_tun=>["亀梨", "上田", "中丸"]}

定数のネストした配列に変更を加えましたがエラーが出ませんね。

ネストの深くまで freeze させるためには、 gem 'ice_nine'deep_freeze メソッド を使います。(導入方法はこちら)
※ 他にも同じような gem はあると思いますので何を使っても大丈夫です。

変更を加えようとするとちゃんとエラーが出てますね。

irb(main):001:0> JOHNNYS_MEMBERS = {arashi: ["大野", "松本", "二宮", "桜井", "相葉"] , kat_tun:['亀梨', '上田', '中丸']}.freeze
irb(main):002:0> JOHNNYS_MEMBERS[:arashi] << ' 木村'
Traceback (most recent call last):
        4: from /Users/dan/.rbenv/versions/2.7.1/bin/irb:23:in `<main>'
        3: from /Users/dan/.rbenv/versions/2.7.1/bin/irb:23:in `load'
        2: from /Users/dan/.rbenv/versions/2.7.1/lib/ruby/gems/2.7.0/gems/irb-1.2.3/exe/irb:11:in `<top (required)>'
        1: from (irb):8
FrozenError (can't modify frozen Array: ["大野", "松本", "二宮", "桜井", "相葉"])

応用③ ネストされた Array や Hash の定数を変更して使いたい時

deep_dup メソッドを使いましょう。 ※ こちらは Rails に標準で備わっています。

irb(main):001:0> JOHNNYS_MEMBERS = {arashi: ["大野", "松本", "二宮", "桜井", "相葉"] , kat_tun:['亀梨', '上田', '中丸']}.deep_freeze
irb(main):002:0> tmp_johnnys_members = JOHNNYS_MEMBERS.deep_dup
irb(main):002:0> Jtmp_johnnys_members[:arashi] << ' 木村'
=> ["大野", "松本", "二宮", "桜井", "相葉", " 木村"]
irb(main):003:0> tmp_johnnys_members
=> {:arashi=>["大野", "松本", "二宮", "桜井", "相葉", " 木村"], :kat_tun=>["亀梨", "上田", "中丸"]}
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1