web-dev-qa-db-ja.com

Ruby on Rails:グローバル定数をどこで定義しますか?

Ruby webappで最初のRailsを始めたばかりです。さまざまなモデル、ビュー、コントローラーなどがあります。

アプリ全体に適用される真にグローバルな定数の定義を貼り付けるのに適した場所を見つけたいと思っています。特に、それらは私のモデルのロジックと私の見解で行われた決定の両方に適用されます。 all私のモデルとすべてのビューの両方で利用できる場所にこれらの定義を配置するDRY場所を見つけることができません。

具体的な例を挙げると、定数COLOURS = ['white', 'blue', 'black', 'red', 'green']が必要です。これは、モデルとビューの両方で、至る所で使用されます。アクセスできるように1か所でどこで定義できますか?

私が試したもの:

  • @@COLOURS = [...]など、model.rbファイル内で最も関連付けられている定数クラス変数。しかし、Card.COLOURSのような気が狂ったようなものではなく、自分のビューにCard.first.COLOURSを書くことができるように、それを定義するための健全な方法を見つけることができませんでした。
  • モデル上のメソッド、def colours ['white',...] endのようなもの-同じ問題。
  • Application_helper.rbのメソッド-これは私がこれまでやっていることですが、ヘルパーはモデルではなくビューでのみアクセス可能です
  • 私はapplication.rbまたはenvironment.rbで何かを試したかもしれませんが、それらは実際には正しくないようです(そして彼らも動作していないようです)

モデルとビューの両方からアクセスできるように定義する方法はありませんか?つまり、モデルとビューは分離する必要があることを知っていますが、一部のドメインでは、同じドメイン固有の知識を参照する必要がある場合がありますか?

199
AlexC

モデルが定数に対して本当に「責任がある」場合は、そこに固定する必要があります。新しいオブジェクトインスタンスを作成せずにアクセスするクラスメソッドを作成できます。

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

# accessible like this
Card.colours

または、クラス変数とアクセサーを作成できます。ただし、継承やマルチスレッド環境ではクラス変数が驚くほど動作する可能性があるため、これは推奨されません。

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

# accessible the same as above

上記の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

注:上記の定数を定義するとき、多くの場合、配列をfreezeにする必要があります。これにより、他のコードが後で(意図せずに)新しい要素を追加するなどして配列を変更することを防ぎます。オブジェクトが凍結されると、変更されました。

218
Holger Just

いくつかのオプション:

定数を使用する:

class Card
  COLOURS = ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
end

クラスインスタンス変数を使用した遅延読み込み:

class Card
  def self.colours
    @colours ||= ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
  end
end

それが真のグローバル定数である場合(この性質のグローバル定数は避けてください)、たとえばconfig/initializers/my_constants.rbにトップレベルの定数を置くことも検討できます。

66
Zabba

Rails 4.2以降、 config.x プロパティを使用できます:

# config/application.rb (or config/custom.rb if you prefer)
config.x.colours.options = %w[white blue black red green]
config.x.colours.default = 'white'

次のように利用可能になります:

Rails.configuration.x.colours.options
# => ["white", "blue", "black", "red", "green"]
Rails.configuration.x.colours.default
# => "white"

カスタム設定をロードする別の方法:

# config/colours.yml
default: &default
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white
development:
  *default
production:
  *default
# config/application.rb
config.colours = config_for(:colours)
Rails.configuration.colours
# => {"options"=>["white", "blue", "black", "red", "green"], "default"=>"white"}
Rails.configuration.colours['default']
# => "white"

Rails 56 では、config.xに加えて、configurationオブジェクトをカスタム構成に直接使用できます。ただし、ネストされていない構成にのみ使用できます。

# config/application.rb
config.colours = %w[white blue black red green]

次のように利用できます。

Rails.configuration.colours
# => ["white", "blue", "black", "red", "green"]
51
Halil Özgür

定数が複数のクラスで必要な場合は、常にすべての大文字でconfig/initializers/contant.rbに入れます(以下の状態のリストは切り捨てられます)。

STATES = ['AK', 'AL', ... 'WI', 'WV', 'WY']

これらは、モデルコード自体を除き、アプリケーション全体で利用できます。

    <%= form.label :states, %>
    <%= form.select :states, STATES, {} %>

モデルで定数を使用するには、attr_accessorを使用して定数を使用可能にします。

class Customer < ActiveRecord::Base
    attr_accessor :STATES

    validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end
17
Hank Snow

アプリケーション全体の設定およびグローバル定数の場合、 Settingslogic を使用することをお勧めします。この設定はYMLファイルに保存され、モデル、ビュー、コントローラーからアクセスできます。さらに..すべての環境に異なる設定を作成できます。

  # app/config/application.yml
  defaults: &defaults
    cool:
      saweet: nested settings
    neat_setting: 24
    awesome_setting: <%= "Did you know 5 + 5 = #{5 + 5}?" %>

    colors: "white blue black red green"

  development:
    <<: *defaults
    neat_setting: 800

  test:
    <<: *defaults

  production:
    <<: *defaults

ビューのどこか(このような種類のヘルパーメソッドが好きです)またはモデルで、たとえば色の配列Settings.colors.split(/\s/)を取得できます。とても柔軟です。そして、あなたは自転車を発明する必要はありません。

14
Voldy

クラスメソッドを使用します。

def self.colours
  ['white', 'red', 'black']
end

その後、Model.coloursはその配列を返します。または、初期化子を作成し、モジュールで定数をラップして、名前空間の競合を回避します。

7
Steve Ross

1つの場所で定数を定義する場合の別のオプション:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end

ただし、完全に修飾された方法でアクセスすることなく、グローバルに表示できます。

DSL::Constants::MY_CONSTANT # => 1
MY_CONSTANT # => NameError: uninitialized constant MY_CONSTANT
Object.instance_eval { include DSL::Constants }
MY_CONSTANT # => 1
3
wincent

アプリケーション全体のグローバル定数を置く一般的な場所は、config/applicationの中です。

module MyApp
  FOO ||= ENV.fetch('FOO', nil)
  BAR ||= %w(one two three)

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end
3
Dennis

すべてを一定に保つようにしてください。私のアプリケーションでは、次のように初期化子内に定数フォルダーを作成しました。

enter image description here

通常、これらのファイルではすべてを一定に保ちます。

あなたの場合、あなたは定数フォルダの下にcolors_constant.rbとしてファイルを作成することができます

colors_constant.rb

enter image description here

サーバーの再起動を忘れないでください

2
Ghanshyam Anand

通常、Railsプログラムに「ルックアップ」モデル/テーブルがあり、それを定数に使用します。定数が異なる環境で異なる場合に非常に便利です。さらに、それらを拡張する計画がある場合、たとえば後日「黄色」を追加したい場合は、ルックアップテーブルに新しい行を追加するだけで済みます。

管理者にこのテーブルを変更する許可を与えると、メンテナンスのために管理者にアクセスすることはありません。 :)乾燥します。

移行コードは次のようになります。

class CreateLookups < ActiveRecord::Migration
  def change
    create_table :lookups do |t|
      t.string :group_key
      t.string :lookup_key
      t.string :lookup_value
      t.timestamps
    end
  end
end

Seeds.rbを使用して事前入力します。

Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');
1
SriSri

あなたの条件に応じて、いくつかの環境変数を定義し、RubyコードのENV['some-var']経由で取得することもできます。この解決策はあなたには合わないかもしれませんが、他の人に役立つかもしれません。

例:さまざまなファイル.development_env.production_env.test_envを作成し、アプリケーション環境に応じて読み込むことができます。このgen dotenv-Rails を確認してください。

0
fangxing

グローバル変数はconfig/initializersディレクトリで宣言する必要があります

COLOURS = %w(white blue black red green)
0
bird