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

Ale*_*exC 203 global ruby-on-rails constants

我刚刚开始使用我的第一个Ruby on Rails webapp.我有一堆不同的模型,视图,控制器等等.

我想找到一个好地方来坚持真正全局常量的定义,这适用于我的整个应用程序.特别是,它们既适用于模型的逻辑,也适用于我的观点中的决策.我找不到任何干燥的地方将这些定义放在我们所有模型和我的所有视图中都可用的地方.

举一个具体的例子,我想要一个常数COLOURS = ['white', 'blue', 'black', 'red', 'green'].在模型和视图中都可以使用它.我在哪里可以在一个地方定义它以便它可以访问?

我尝试过的:

  • model.rb文件中与它们关联最多的常量类变量,例如@@COLOURS = [...].但我无法找到一种明智的方式来定义它,以便我可以写出我的观点,Card.COLOURS而不是像kludgy那样的东西Card.first.COLOURS.
  • 关于模型的方法,类似于def colours ['white',...] end- 同样的问题.
  • application_helper.rb中的一个方法 - 这是我到目前为止所做的,但帮助程序只能在视图中访问,而不能在模型中访问
  • 我想我可能在application.rb或environment.rb中尝试了一些东西,但那些看起来并不正确(而且它们似乎也没有用)

是否无法定义任何可从模型和视图访问的内容?我的意思是,我知道模型和视图应该是分开的,但在某些领域肯定会有时候他们需要引用相同的领域特定知识?

Hol*_*ust 223

如果你的模型对常量真的"负责",你应该把它们粘在那里.您可以创建类方法来访问它们,而无需创建新的对象实例:

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

# accessible like this
Card.colours
Run Code Online (Sandbox Code Playgroud)

或者,您可以创建类变量和访问器.然而,这是不鼓励的,因为类变量在继承和多线程环境中可能会令人惊讶.

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

# accessible the same as above
Run Code Online (Sandbox Code Playgroud)

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

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

# accessible as
Card::COLOURS
Run Code Online (Sandbox Code Playgroud)

您还可以创建全局常量,这些常量可以在初始化程序中的任何位置访问,如下例所示.如果您的颜色真的是全局的并且在多个模型上下文中使用,那么这可能是最佳位置.

# put this into config/initializers/my_constants.rb
COLOURS = ['white', 'blue'].freeze
Run Code Online (Sandbox Code Playgroud)

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

  • 如果进入`config/initializers/my_constants.rb`路由,请记住重启服务器:`touch tmp/restart.txt` (19认同)
  • `def self.colours`的例子并不理想.每次调用`def self.colours`时,*都会返回一个新的数组实例*.在这种情况下,`#freeze`无济于事.最佳做法是将其声明为Ruby常量,在这种情况下,您将始终返回相同的对象. (4认同)
  • 非常感谢。看起来我缺少 Ruby class-fu 来定义类方法。但我实际上喜欢这种情况下的初始化选项,因为颜色在多个模型和视图中使用。非常感谢! (2认同)

Zab*_*bba 67

一些选择:

使用常量:

class Card
  COLOURS = ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
end
Run Code Online (Sandbox Code Playgroud)

使用类实例变量加载延迟:

class Card
  def self.colours
    @colours ||= ['white', 'blue', 'black', 'red', 'green', 'yellow'].freeze
  end
end
Run Code Online (Sandbox Code Playgroud)

如果它是一个真正的全局常量(尽管避免了这种性质的全局常量),你也可以考虑将顶层常量放在config/initializers/my_constants.rb例如中.

  • 然后`扩展'类中的模块,以便它可以与`Card.COLOURS`一起使用. (2认同)

Hal*_*gür 53

从Rails 5.0开始,您可以config.x直接使用该对象进行自定义配置:

configuration(或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'
Run Code Online (Sandbox Code Playgroud)

它将作为:

Rails.configuration.x.colours.options
# => ["white", "blue", "black", "red", "green"]
Rails.configuration.x.colours.default
# => "white"
Run Code Online (Sandbox Code Playgroud)

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

# config/colours.yml
default: &default
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white
development:
  *default
production:
  *default
Run Code Online (Sandbox Code Playgroud)

哪个可用:

# config/application.rb
config.colours = config_for(:colours)
Run Code Online (Sandbox Code Playgroud)

  • 我最喜欢 `Rails.configuration.colours` (尽管我希望它不要那么长) (2认同)

小智 17

如果在多个类中需要一个常量,我将它放在config/initializers/contant.rb中,总是全部大写(下面的状态列表被截断).

STATES = ['AK', 'AL', ... 'WI', 'WV', 'WY']
Run Code Online (Sandbox Code Playgroud)

除了模型代码之外,它们可以在整个应用程序中使用:

    <%= form.label :states, %>
    <%= form.select :states, STATES, {} %>
Run Code Online (Sandbox Code Playgroud)

要在模型中使用常量,请使用attr_accessor使常量可用.

class Customer < ActiveRecord::Base
    attr_accessor :STATES

    validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end
Run Code Online (Sandbox Code Playgroud)


Vol*_*ldy 15

对于应用程序范围的设置和全局常量,我建议使用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
Run Code Online (Sandbox Code Playgroud)

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


Ste*_*oss 7

使用类方法:

def self.colours
  ['white', 'red', 'black']
end
Run Code Online (Sandbox Code Playgroud)

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


Gha*_*and 7

尝试将所有内容保持在一个位置,在我的应用程序中,我在初始化程序中创建了常量文件夹,如下所示:

在此处输入图片说明

我通常在这些文件中保持所有不变。

在您的情况下,您可以在常量文件夹下创建文件作为 colors_constant.rb

颜色常量.rb

在此处输入图片说明

不要忘记重启服务器

  • 这是我在这里找到的最佳答案。谢谢。 (2认同)

win*_*ent 5

如果您想在一个地方定义常量,另一种选择是:

module DSL
  module Constants
    MY_CONSTANT = 1
  end
end
Run Code Online (Sandbox Code Playgroud)

但仍然使它们全局可见,而无需以完全限定的方式访问它们:

DSL::Constants::MY_CONSTANT # => 1
MY_CONSTANT # => NameError: uninitialized constant MY_CONSTANT
Object.instance_eval { include DSL::Constants }
MY_CONSTANT # => 1
Run Code Online (Sandbox Code Playgroud)