Ruby on Rails:在哪里定义全局常量?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/4110866/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Ruby on Rails: Where to define global constants?
提问by AlexC
I'm just getting started with my first Ruby on Rails webapp. I've got a bunch of different models, views, controllers, and so on.
我刚刚开始使用我的第一个 Ruby on Rails webapp。我有一堆不同的模型、视图、控制器等等。
I'm wanting to find a good place to stick definitions of truly global constants, that apply across my whole app. In particular, they apply both in the logic of my models, and in the decisions taken in my views. I cannot find any DRY place to put these definitions where they're available both to allmy models and also in all my views.
我想找到一个好地方来坚持真正全局常量的定义,这些定义适用于我的整个应用程序。特别是,它们既适用于我的模型逻辑,也适用于我的观点中做出的决定。我找不到任何干燥的地方来放置这些定义,它们既可用于我的所有模型,也可用于我的所有视图。
To take a specific example, I want a constant COLOURS = ['white', 'blue', 'black', 'red', 'green']. This is used all over the place, in both models and views. Where can I define it in just one place so that it's accessible?
举一个具体的例子,我想要一个常量COLOURS = ['white', 'blue', 'black', 'red', 'green']. 这在模型和视图中无处不在。我在哪里可以在一个地方定义它以便它可以访问?
What I've tried:
我试过的:
- Constant class variables in the model.rb file that they're most associated with, such as
@@COLOURS = [...]. But I couldn't find a sane way to define it so that I can write in my viewsCard.COLOURSrather than something kludgy likeCard.first.COLOURS. - A method on the model, something like
def colours ['white',...] end- same problem. - A method in application_helper.rb - this is what I'm doing so far, but the helpers are only accessible in views, not in models
- I think I might have tried something in application.rb or environment.rb, but those don't really seem right (and they don't seem to work either)
- model.rb 文件中与它们最相关的常量类变量,例如
@@COLOURS = [...]. 但我找不到一种理智的方式来定义它,这样我就可以写出我的观点,Card.COLOURS而不是像Card.first.COLOURS. - 模型上的一种方法,类似于
def colours ['white',...] end- 同样的问题。 - application_helper.rb 中的一种方法 - 这是我目前正在做的,但助手只能在视图中访问,而不是在模型中
- 我想我可能在 application.rb 或 environment.rb 中尝试过一些东西,但那些看起来并不正确(而且它们似乎也不起作用)
Is there just no way to define anything to be accessible both from models and from views? I mean, I know models and views should be separate, but surely in some domains there'll be times they need to refer to the same domain-specific knowledge?
有没有办法定义任何东西都可以从模型和视图访问?我的意思是,我知道模型和视图应该是分开的,但是在某些领域中肯定会有时间它们需要引用相同的特定于领域的知识?
回答by Holger Just
If your model is really "responsible" for the constants you should stick them there. You can create class methods to access them without creating a new object instance:
如果你的模型真的对常量“负责”,你应该把它们放在那里。您可以创建类方法来访问它们,而无需创建新的对象实例:
class Card < ActiveRecord::Base
def self.colours
['white', 'blue']
end
end
# accessible like this
Card.colours
Alternatively, you can create class variables and an accessor. This is however discouraged as class variables might act kind of surprising with inheritance and in multi-thread environments.
或者,您可以创建类变量和访问器。然而,这是不鼓励的,因为类变量在继承和多线程环境中可能会表现得令人惊讶。
class Card < ActiveRecord::Base
@@colours = ['white', 'blue']
cattr_reader :colours
end
# accessible the same as above
The two options above allow you to change the returned array on each invocation of the accessor method if required. If you have true a truly unchangeable constant, you can also define it on the model class:
如果需要,上面的两个选项允许您在每次调用访问器方法时更改返回的数组。如果你有一个真正不可更改的常量,你也可以在模型类上定义它:
class Card < ActiveRecord::Base
COLOURS = ['white', 'blue'].freeze
end
# accessible as
Card::COLOURS
You could also create global constants which are accessible from everywhere in an initializer like in the following example. This is probably the best place, if your colours are really global and used in more than one model context.
您还可以在初始化程序中创建可从任何地方访问的全局常量,如下例所示。这可能是最好的地方,如果您的颜色真的是全局的并且在多个模型上下文中使用。
# put this into config/initializers/my_constants.rb
COLOURS = ['white', 'blue'].freeze
Note: when we define constants above, often we want to freezethe array. That prevents other code from later (inadvertently) modifying the array by e.g. adding a new element. Once an object is frozen, it can't be changed anymore.
注意:当我们在上面定义常量时,通常我们想要freeze数组。这可以防止其他代码稍后(无意中)通过添加新元素来修改数组。一旦一个对象被冻结,它就不能再改变了。
回答by Zabba
Some options:
一些选项:
Using a constant:
使用常量:
class Card
COLOURS = ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
end
Lazy loaded using class instance variable:
使用类实例变量延迟加载:
class Card
def self.colours
@colours ||= ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
end
end
If it is a truly global constant (avoid global constants of this nature, though), you could also consider putting
a top-level constant in config/initializers/my_constants.rbfor example.
如果它是一个真正的全局常量(尽管避免使用这种性质的全局常量),您还可以考虑放入一个顶级常量,config/initializers/my_constants.rb例如。
回答by Halil ?zgür
As of Rails 4.2, you can use the config.xproperty:
从 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'
Which will be available as:
这将作为:
Rails.configuration.x.colours.options
# => ["white", "blue", "black", "red", "green"]
Rails.configuration.x.colours.default
# => "white"
Another method of loading custom config:
另一种加载自定义配置的方法:
# 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"
In Rails 5& 6, you can use the configurationobject directly for custom configuration, in addition to config.x. However, it can only be used for non-nested configuration:
在 Rails 5& 6 中,configuration除了config.x. 但是,它只能用于非嵌套配置:
# config/application.rb
config.colours = %w[white blue black red green]
It will be available as:
它将作为:
Rails.configuration.colours
# => ["white", "blue", "black", "red", "green"]
回答by Hank Snow
If a constant is needed in more than one class, I put it in config/initializers/contant.rb always in all caps (list of states below is truncated).
如果在一个以上的类中需要一个常量,我将它放在 config/initializers/contant.rb 中,总是全部大写(下面的状态列表被截断)。
STATES = ['AK', 'AL', ... 'WI', 'WV', 'WY']
They are available through out the application except in model code as such:
它们在整个应用程序中都可用,但在模型代码中除外:
<%= form.label :states, %>
<%= form.select :states, STATES, {} %>
To use the constant in a model, use attr_accessor to make the constant available.
要在模型中使用常量,请使用 attr_accessor 使常量可用。
class Customer < ActiveRecord::Base
attr_accessor :STATES
validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end
回答by Voldy
For application-wide settings and for global constants I recommend to use Settingslogic. This settings are stored in YML file and can be accessed from models, views and controllers. Furthermore, you can create different settings for all your environments:
对于应用程序范围的设置和全局常量,我建议使用Settingslogic。这些设置存储在 YML 文件中,可以从模型、视图和控制器访问。此外,您可以为所有环境创建不同的设置:
# app/config/application.yml
defaults: &defaults
cool:
sweet: 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
Somewhere in the view (I prefer helper methods for such kind of stuff) or in a model you can get, for ex., array of colors Settings.colors.split(/\s/). It's very flexible. And you don't need to invent a bike.
在视图中的某个地方(我更喜欢此类东西的辅助方法)或在模型中您可以获得,例如,颜色数组Settings.colors.split(/\s/)。它非常灵活。你不需要发明一辆自行车。
回答by Steve Ross
Use a class method:
使用类方法:
def self.colours
['white', 'red', 'black']
end
Then Model.colourswill return that array. Alternatively, create an initializer and wrap the constants in a module to avoid namespace conflicts.
然后Model.colours将返回该数组。或者,创建一个初始化程序并将常量包装在一个模块中以避免命名空间冲突。
回答by wincent
Another option, if you want to define your constants in one place:
另一种选择,如果你想在一个地方定义你的常量:
module DSL
module Constants
MY_CONSTANT = 1
end
end
But still make them globally visible without having to access them in fully qualified way:
但仍然使它们全局可见,而无需以完全限定的方式访问它们:
DSL::Constants::MY_CONSTANT # => 1
MY_CONSTANT # => NameError: uninitialized constant MY_CONSTANT
Object.instance_eval { include DSL::Constants }
MY_CONSTANT # => 1
回答by Dennis
A common place to put application-wide global constantsis inside config/application.
放置应用程序范围的全局常量的一个常见位置是在config/application.
module MyApp
FOO ||= ENV.fetch('FOO', nil)
BAR ||= %w(one two three)
class Application < Rails::Application
config.foo_bar = :baz
end
end
回答by Ghanshyam Anand
Try to keep all constant at one place, In my application I have created constants folder inside initializers as follows:
尝试将所有常量保持在一个位置,在我的应用程序中,我在初始化程序中创建了常量文件夹,如下所示:
and I usually keep all constant in these files.
我通常在这些文件中保持所有不变。
In your case you can create file under constants folder as colors_constant.rb
在您的情况下,您可以在常量文件夹下创建文件作为 colors_constant.rb
colors_constant.rb
颜色常量.rb
Don't forgot to restart server
不要忘记重启服务器
回答by SriSri
I typically have a 'lookup' model/table in my rails program and use it for the constants. It is very useful if the constants are going to be different for different environments. In addition, if you have a plan to extend them, say you want to add 'yellow' on a later date, you could simply add a new row to the lookup table and be done with it.
我的 rails 程序中通常有一个“查找”模型/表,并将其用于常量。如果常量对于不同的环境会有所不同,这将非常有用。此外,如果您有扩展它们的计划,假设您想在以后添加“黄色”,您可以简单地向查找表添加一个新行并完成它。
If you give the admin permissions to modify this table, they will not come to you for maintenance. :) DRY.
如果您授予管理员修改此表的权限,他们将不会来找您进行维护。:) 干燥。
Here is how my migration code looks like:
这是我的迁移代码的样子:
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
I use seeds.rb to pre-populate it.
我使用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');


