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

发布于 2024-09-30 12:51:26 字数 768 浏览 5 评论 0原文

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

我想找到一个好地方来保存真正全局常量的定义,这些常量适用于我的整个应用程序。特别是,它们既适用于我的模型的逻辑,也适用于我的观点所做出的决定。我找不到任何干燥的地方来放置这些定义,它们既适用于我的所有模型,也适用于我的所有视图。

举一个具体的例子,我想要一个常量COLOURS = ['white', 'blue', 'black', 'red', 'green']。这在模型和视图中随处可见。我可以在哪里将其定义在一处以便可以访问吗?

我尝试过的方法:

  • model.rb 文件中与它们最相关的常量类变量,例如 @@COLOURS = [...]。但我找不到一种合理的方法来定义它,以便我可以在视图中编写 Card.COLOURS 而不是像 Card.first.COLOURS 这样的笨拙的东西。
  • 模型上的方法,例如 def color ['white',...] end - 同样的问题。
  • application_helper.rb 中的方法 - 这就是我到目前为止所做的,但助手只能在视图中访问,而不是在模型中
  • 访问看起来真的很正确(而且它们似乎也不起作用)

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

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.

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 all my 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?

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

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?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(13

墨落成白 2024-10-07 12:51:26

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

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

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

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'].freeze
  cattr_reader :colours
end

# accessible the same as above
Card.colours

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

# accessible as a top-level constant this time
COLOURS

Note: when we define constants above, often we want to freeze the 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.

往日情怀 2024-10-07 12:51:26

一些选项:

使用常量:

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 中的顶级常量。

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.rb for example.

数理化全能战士 2024-10-07 12:51:26

从 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 中 56 ,并且 7 您可以使用配置 对象。但是,它只能用于非嵌套配置:

# config/application.rb
config.colours = %w[white blue black red green]

它将作为以下形式提供:

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

Rails 6.1 引入了可以简化 YML 配置的 shared 组:

# config/colours.yml
shared:
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white

As of Rails 4.2, you can use the config.x property:

# 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, and 7 you can use the configuration object directly for custom configuration, in addition to config.x. However, it can only be used for non-nested configuration:

# config/application.rb
config.colours = %w[white blue black red green]

It will be available as:

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

Rails 6.1 introduced shared groups which can simplify YML configs:

# config/colours.yml
shared:
  options:
    - white
    - blue
    - black
    - red
    - green
  default: white
_蜘蛛 2024-10-07 12:51:26

如果多个类需要一个常量,我将它放在 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

If a constant is needed in more than one class, I put it in config/initializers/constant.rb always in all caps (list of states below is truncated).

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.

class Customer < ActiveRecord::Base
    attr_accessor :STATES

    validates :state, inclusion: {in: STATES, message: "-- choose a State from the drop down list."}
end
猫七 2024-10-07 12:51:26

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

在视图中的某个位置(我更喜欢此类内容的辅助方法)或在模型中,您可以获得例如颜色数组 Settings.colors.split (/\s/)。它非常灵活。而且你不需要发明自行车。

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:

  # 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.

旧伤还要旧人安 2024-10-07 12:51:26

尝试将所有常量保留在一处,在我的应用程序中,我在初始化程序中创建了常量文件夹,如下所示:

在此处输入图像描述

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

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

colors_constant.rb

在此处输入图像描述

不要忘记重新启动服务器

Try to keep all constant at one place, In my application I have created constants folder inside initializers as follows:

enter image description here

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

enter image description here

Don't forgot to restart server

凤舞天涯 2024-10-07 12:51:26

使用类方法:

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

然后 Model.colours 将返回该数组。或者,创建一个初始值设定项并将常量包装在模块中以避免命名空间冲突。

Use a class method:

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

Then Model.colours will return that array. Alternatively, create an initializer and wrap the constants in a module to avoid namespace conflicts.

短叹 2024-10-07 12:51:26

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

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

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
眼泪也成诗 2024-10-07 12:51:26

放置应用程序范围的全局常量的常见位置是config/application内部。

module MyApp
  FOO ||= ENV.fetch('FOO', nil)
  BAR ||= %w(one two three)

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end

A common place to put application-wide global constants is inside config/application.

module MyApp
  FOO ||= ENV.fetch('FOO', nil)
  BAR ||= %w(one two three)

  class Application < Rails::Application
    config.foo_bar = :baz
  end
end
软糯酥胸 2024-10-07 12:51:26

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

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.

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.

Lookup.find_or_create_by_group_key_and_lookup_key_and_lookup_value!(group_key: 'development_COLORS', lookup_key: 'color1', lookup_value: 'red');
放低过去 2024-10-07 12:51:26

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

COLOURS = %w(white blue black red green)

The global variable should be declare in config/initializers directory

COLOURS = %w(white blue black red green)
单调的奢华 2024-10-07 12:51:26

根据您的情况,您还可以定义一些环境变量,并通过 ruby​​ 代码中的 ENV['some-var'] 获取它,这个解决方案可能不适合您,但我希望它可以帮助其他人。

示例:您可以创建不同的文件 .development_env.development_env.test_env 并根据您的应用程序环境加载它,检查此 gen dotenv-rails 可以自动完成此操作。

According your condition, you can also define some environmental variables, and fetch it via ENV['some-var'] in ruby code, this solution may not fit for you, but I hope it may help others.

Example: you can create different files .development_env, .production_env, .test_env and load it according your application environments, check this gen dotenv-rails which automate this for your.

三寸金莲 2024-10-07 12:51:26

我认为你可以使用 gem config

https://github.com/rubyconfig/config< /a>

轻松处理和编辑

I think you can use gem config

https://github.com/rubyconfig/config

Easy handle and edit

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文