Ruby webappで最初のRailsを始めたばかりです。さまざまなモデル、ビュー、コントローラーなどがあります。
アプリ全体に適用される真にグローバルな定数の定義を貼り付けるのに適した場所を見つけたいと思っています。特に、それらは私のモデルのロジックと私の見解で行われた決定の両方に適用されます。 all私のモデルとすべてのビューの両方で利用できる場所にこれらの定義を配置するDRY場所を見つけることができません。
具体的な例を挙げると、定数COLOURS = ['white', 'blue', 'black', 'red', 'green']
が必要です。これは、モデルとビューの両方で、至る所で使用されます。アクセスできるように1か所でどこで定義できますか?
私が試したもの:
@@COLOURS = [...]
など、model.rbファイル内で最も関連付けられている定数クラス変数。しかし、Card.COLOURS
のような気が狂ったようなものではなく、自分のビューにCard.first.COLOURS
を書くことができるように、それを定義するための健全な方法を見つけることができませんでした。def colours ['white',...] end
のようなもの-同じ問題。モデルとビューの両方からアクセスできるように定義する方法はありませんか?つまり、モデルとビューは分離する必要があることを知っていますが、一部のドメインでは、同じドメイン固有の知識を参照する必要がある場合がありますか?
モデルが定数に対して本当に「責任がある」場合は、そこに固定する必要があります。新しいオブジェクトインスタンスを作成せずにアクセスするクラスメソッドを作成できます。
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
にする必要があります。これにより、他のコードが後で(意図せずに)新しい要素を追加するなどして配列を変更することを防ぎます。オブジェクトが凍結されると、変更されました。
いくつかのオプション:
定数を使用する:
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
にトップレベルの定数を置くことも検討できます。
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 5 & 6 では、config.x
に加えて、configuration
オブジェクトをカスタム構成に直接使用できます。ただし、ネストされていない構成にのみ使用できます。
# config/application.rb
config.colours = %w[white blue black red green]
次のように利用できます。
Rails.configuration.colours
# => ["white", "blue", "black", "red", "green"]
定数が複数のクラスで必要な場合は、常にすべての大文字で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
アプリケーション全体の設定およびグローバル定数の場合、 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/)
を取得できます。とても柔軟です。そして、あなたは自転車を発明する必要はありません。
クラスメソッドを使用します。
def self.colours
['white', 'red', 'black']
end
その後、Model.colours
はその配列を返します。または、初期化子を作成し、モジュールで定数をラップして、名前空間の競合を回避します。
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
アプリケーション全体のグローバル定数を置く一般的な場所は、config/application
の中です。
module MyApp
FOO ||= ENV.fetch('FOO', nil)
BAR ||= %w(one two three)
class Application < Rails::Application
config.foo_bar = :baz
end
end
通常、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');
あなたの条件に応じて、いくつかの環境変数を定義し、RubyコードのENV['some-var']
経由で取得することもできます。この解決策はあなたには合わないかもしれませんが、他の人に役立つかもしれません。
例:さまざまなファイル.development_env
、.production_env
、.test_env
を作成し、アプリケーション環境に応じて読み込むことができます。このgen dotenv-Rails を確認してください。
グローバル変数はconfig/initializers
ディレクトリで宣言する必要があります
COLOURS = %w(white blue black red green)