1. ホーム
  2. ruby-on-rails

[解決済み】Ruby on Rails。グローバル定数を定義する場所はどこですか?

2022-04-05 04:24:54

質問

初めてのRuby on RailsのWebアプリを始めたところです。モデル、ビュー、コントローラなど、さまざまなものを用意しています。

アプリ全体に適用されるグローバルな定数を定義するのに適した場所を見つけたいのです。特に、モデルのロジックと、ビューでの決定の両方に適用されます。これらの定数を置くためのDRYな場所を見つけることができません。 すべて のモデル、そしてすべてのビューで使用することができます。

具体的な例を挙げると、定数 COLOURS = ['white', 'blue', 'black', 'red', 'green'] . これは、モデルでもビューでもあちこちで使われています。これを一カ所だけ定義して、アクセスできるようにするにはどうしたらよいでしょうか?

試してみたこと

  • model.rbファイルの中で、最も関連性の高いクラス変数を、以下のように定数化する。 @@COLOURS = [...] . しかし、ビューに書けるように定義するまともな方法が見つかりませんでした。 Card.COLOURS というような不格好なものでなく Card.first.COLOURS .
  • モデル上のメソッドで、次のようなものです。 def colours ['white',...] end - 同じ問題です。
  • application_helper.rbのメソッド - これは私が今のところやっていることですが、ヘルパーはモデルではなくビューでのみアクセス可能です。
  • application.rbやenvironment.rbで何か試したかもしれませんが、それらは本当に正しいとは思えません(そして、それらも動作しないようです)。

モデルからもビューからもアクセスできるように何かを定義する方法はないのでしょうか?つまり、モデルとビューは別々であるべきだということは分かっていますが、確かにドメインによっては同じドメイン固有の知識を参照する必要がある場合もあるのではないでしょうか?

解決方法は?

もしあなたのモデルが本当に定数に対して責任があるのなら、定数をそこに貼り付けるべきです。新しいオブジェクトのインスタンスを作成することなく、それらにアクセスするためのクラスメソッドを作成することができます。

class Card < ActiveRecord::Base
  def self.colours
    ['white', 'blue']
  end
end

# accessible like this
Card.colours

また、クラス変数とアクセッサを作成することもできます。しかし、クラス変数は継承やマルチスレッド環境では意外な動作をすることがあるので、この方法はお勧めしません。

class Card < ActiveRecord::Base
  @@colours = ['white', 'blue'].freeze
  cattr_reader :colours
end

# accessible the same as above
Card.colours

上の 2 つのオプションを使用すると、 必要に応じてアクセッサメソッドを呼び出すたびに返される配列を変更することができます。もし、本当に変更できない定数があるのなら、モデルクラスで定義することもできます。

class Card < ActiveRecord::Base
  COLOURS = ['white', 'blue'].freeze
end

# accessible as
Card::COLOURS

また、次の例のように、イニシャライザーでどこからでもアクセスできるグローバル定数を作成することもできます。あなたの色が本当にグローバルで、複数のモデルコンテキストで使用される場合、これはおそらく最良の場所でしょう。

# put this into config/initializers/my_constants.rb
COLOURS = ['white', 'blue'].freeze

# accessible as a top-level constant this time
COLOURS

注:上記の定数を定義する場合、多くの場合、以下のようにしたい。 freeze を配列に追加します。これは、他のコードが後で(不注意に)例えば新しい要素を追加することによって配列を変更するのを防ぐためです。オブジェクトは一度凍結されると、もう変更することはできません。