我刚刚开始使用我的第一个Ruby on Rails web应用程序。我有很多不同的模型,视图,控制器等等。
我想找到一个好地方粘真正的全局常数的定义,适用于我的整个应用程序。特别是,它们适用于我的模型的逻辑,并在我的视图中所做的决定。我找不到任何DRY的地方来放置这些定义,它们既适用于我的所有模型,也适用于我的所有视图。
举个具体的例子,我想要一个常量colors = ['white', 'blue', 'black', 'red', 'green']。这在模型和视图中都被广泛使用。我可以在哪里只在一个地方定义它,以便它是可访问的?
我的尝试:
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 views Card.COLOURS rather than something kludgy like Card.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)
是否没有办法定义从模型和视图都可以访问的东西?我的意思是,我知道模型和视图应该是分开的,但在某些领域,它们肯定会有需要引用相同的领域特定知识的时候?
如果你的模型真的对常数“负责”,你应该把它们放在那里。你可以创建类方法来访问它们,而不需要创建新的对象实例:
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
如果需要,上面的两个选项允许您在每次调用访问器方法时更改返回的数组。如果你有一个真正不可改变的常数,你也可以在模型类中定义它:
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
注意:当我们在上面定义常量时,通常我们想要冻结数组。这可以防止其他代码以后(无意中)修改数组,例如添加一个新元素。一旦一个对象被冻结,它就不能再改变了。
一些选项:
使用常量:
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
如果它是一个真正的全局常数(但是要避免这种性质的全局常数),您还可以考虑put
config/initializers/my_constants中的顶级常量。比如Rb。
如果一个常量在多个类中需要,我会把它放在config/initializers/constant中。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
从Rails 4.2开始,您可以使用配置。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和7中,除了config.x,您还可以直接使用配置对象进行自定义配置。但是,它只能用于非嵌套配置:
# config/application.rb
config.colours = %w[white blue black red green]
它将以以下方式提供:
Rails.configuration.colours
# => ["white", "blue", "black", "red", "green"]
Rails 6.1引入了可以简化YML配置的共享组:
# config/colours.yml
shared:
options:
- white
- blue
- black
- red
- green
default: white
我通常在我的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
我用种子。Rb来预填充它。
Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');