Ruby on Rails:在哪里定义全局常量?

我刚刚开始使用我的第一个Ruby on Rails web应用程序。 我有很多不同的模型,视图,控制器等等。

我想find一个很好的地方来粘贴真正的全局常量的定义,适用于我的整个应用程序。 特别是,它们既适用于我的模型的逻辑,也适用于我的看法。 我找不到任何干燥的地方,把这些定义放在所有模型和我所有的观点中。

举一个具体的例子,我想要一个常量COLOURS = ['white', 'blue', 'black', 'red', 'green'] 。 这是用在所有的地方,在模型和意见。 我在哪里可以在一个地方定义它,以便可以访问?

我试过了:

  • 与model.rb文件最相关的常量类variables,例如@@COLOURS = [...] 。 但是我找不到一个理智的方式来定义它,这样我就可以在Card.COLOURS视图中写入,而不是像Card.first.COLOURS那样的Card.first.COLOURS
  • 在模型上的一个方法,就像def colours ['white',...] end一样 – 同样的问题。
  • application_helper.rb中的一个方法 – 这是我到目前为止所做的,但助手只能在视图中访问,而不能在模型中访问
  • 我想我可能已经在application.rb或environment.rb中尝试了一些东西,但这些看起来并不正确(而且它们似乎也不工作)

有没有办法来定义任何模型和视图都可以访问? 我的意思是,我知道模型和观点应该是分开的,但是在某些领域肯定会有时间需要引用相同的领域特定知识?

如果你的模型对于常量真的是“负责任的”,你应该把它们粘在那里。 您可以创build类方法来访问它们而不创build新的对象实例:

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

或者,您可以创build类variables和访问器。 然而这是令人沮丧的,因为类variables在inheritance和multithreading环境中可能会令人惊讶。

 class Card < ActiveRecord::Base @@colours = ['white', 'blue'] cattr_reader :colours end # accessible the same as above 

上述两个选项允许您在每次调用访问器方法时更改返回的数组(如果需要)。 如果你有一个真正的不变的常量,你也可以在模型类上定义它:

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

您还可以创build全局常量,这些常量可以在初始化程序中的任何地方访问,如下例所示。 这可能是最好的地方,如果你的颜色真的是全球性的,并在不止一个模型的情况下使用。

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

注意:当我们定义上面的常量时,通常我们要freeze数组。 这可以防止其他代码从后来(无意中)通过例如添加新元素来修改数组。 一旦对象被冻结,它就不能再被改变。

一些选项:

使用常数:

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

使用类实例variables延迟加载:

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

如果它是一个真正的全局常量( 尽pipe避免了这种性质的全局常量 ),那么也可以考虑在config/initializers/my_constants.rb放置一个顶级常量。

从Rails 5.0开始,您可以直接使用configuration对象进行自定义configuration :

config/application.rb (或者config/custom.rb如果你愿意的话)

 config.colours = %w(white blue black red green) 

它将作为:

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

注意:对于4.2版本,您需要使用config.x属性:

 config.x.colours = %w(white blue black red green) 

这将可用作为:

 Rails.configuration.x.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文件中,可以从模型,视图和控制器访问。 更多..你可以为你所有的环境创build不同的设置:

  # 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 

在视图的某个地方(我更喜欢这种types的东西的辅助方法),或者在一个你可以得到的模型中,比如颜色数组Settings.colors.split(/\s/) 。 这非常灵活。 而且你不需要发明一辆自行车。

使用类方法:

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

然后Model.colours将返回该数组。 或者,创build一个初始化程序并将这些常量包装在模块中以避免名称空间冲突。

应用程序范围的全局常量放在一个常见的地方是在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程序中有一个“lookup”模型/表,并将其用于常量。 如果常数在不同的环境下会有所不同,这是非常有用的。 另外,如果你有一个计划去扩展它们,比如说你想在以后的日子里添加“黄色”,那么你可以简单地在查找表中添加一个新行,然后完成它。

如果你给pipe理员权限修改这个表,他们不会来维护。 :)干。

以下是我的迁移代码的样子:

 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'); 

另一个选项,如果你想在一个地方定义你的常量:

 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 

全局variables应该在config/initializers目录中声明

 COLOURS = %w(white blue black red green)