首页 文章

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

提问于
浏览
189

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

我'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'既可用于我的所有模型,也可用于我的所有视图 .

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

我尝试过的:

  • model.rb文件中与它们关联最多的常量类变量,例如 @@COLOURS = [...] . 但我无法找到一种明智的方式来定义它,以便我可以在我的观点中写下 Card.COLOURS 而不是像 Card.first.COLOURS 这样的kludgy .

  • 模型上的方法,如 def colours ['white',...] end - 同样的问题 .

  • application_helper.rb中的一个方法 - 这是我到目前为止所做的,但帮助程序只能在视图中访问,而不能在模型中访问

  • 我想我可能在application.rb或environment.rb中尝试了一些东西,但是那些似乎也没有用过)

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

12 回答

  • 7

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

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

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

    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
    

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

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

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

  • 3

    一些选择:

    使用常量:

    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
    

    如果它是一个真正的全局常量( avoid global constants of this nature, though ),您还可以考虑在 config/initializers/my_constants.rb 中放置一个顶级常量 .

  • 14

    从Rails 5.0开始,您可以直接将 configuration 对象用于custom configuration

    config/application.rb (如果您愿意,可以 config/custom.rb

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

    它将作为:

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

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

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

    哪个可用:

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

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

    对于应用程序范围的设置和全局常量,我建议使用Settingslogic . 此设置存储在YML文件中,可以从模型,视图和控制器访问 . 更多..您可以为所有环境创建不同的设置:

    # 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
    

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

  • 47

    使用类方法:

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

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

  • 64

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

    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
    
  • 205

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

    module MyApp
      FOO ||= ENV.fetch('FOO', nil)
      BAR ||= %w(one two three)
    
      class Application < Rails::Application
        config.foo_bar = :baz
      end
    end
    
  • 1

    我通常在我的rails程序中有一个'lookup'模型/表,并将它用于常量 . 如果常量对于不同的环境会有所不同,那么它非常有用 . 此外,如果您有计划扩展它们,请说要添加“黄色”稍后,您可以简单地向查找表添加一个新行并完成它 .

    如果您授予管理员权限以修改此表,则他们不会来找您进行维护 . :)干 .

    以下是我的迁移代码的外观:

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

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

    COLOURS = %w(white blue black red green)
    
  • 0

    根据你的条件,你也可以定义一些环境变量,并通过ruby代码中的 ENV['some-var'] 获取它,这个解决方案可能不适合你,但我希望它可以帮助别人 .

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

  • 3

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

    enter image description here

    我通常会在这些文件中保持不变 .

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

    colors_constant.rb

    enter image description here

    Don't forgot to restart server

相关问题