在 Rails 中加载 YML 文件,并可能改用 i18n 文件

Loading a YML file in Rails, and maybe using a i18n file instead

我有一个 dropdown.yml 文件,用于存储表单中多 select 字段的所有下拉值。它不依赖于环境,所以我没有 :development、:production 等

我想将文件缓存到一个常量中,以便我可以在我的应用程序中使用。我找到了这个命令。

config = Rails.application.config_for(:payment)

但是,它看起来像依赖于环境。添加 yml 的最佳方式是什么?

其次,我应该为此使用语言环境而不是自定义 yml 文件吗?

config/dropdown.yml

dropdown:
  car_model:
    field1:
      yes: true
       no: false
    region:
      US: United States
      CA: Canada

此外,有没有一种方法可以从多个名称访问下拉菜单?

dropdown:
  car_model| truck_model| bike_model:
    field1:
      yes: true
       no: false
    region:
      US: United States
      CA: Canada

这样我就可以从任何名称键 car_model、truck_model 或 bike_model?

中引用 field1

将其加载到配置块内的 application.rb:

class Application < Rails::Application
  ...
  config.dropdowns = HashWithIndifferentAccess.new(YAML.load_file(File.join(Rails.root, 'config', 'dropdown.yml')))
  ...
end

通过`Rails.application.config.dropdown[:key]

在代码中使用

注意:我会删除顶级下拉键,或者将其添加到加载行的末尾,这样您就不需要在每次需要配置时都调用它。例如

HashWithIndifferentAccess.new(YAML.load_file(File.join(Rails.root, 'config', 'dropdown.yml')))[:dropdown]

也可以将它放入您的 application.rb 中的常量中:

MY_CONST = HashWithIndifferentAccess.new(YAML.load_file(File.join(Rails.root, 'config', 'dropdown.yml')))

我想我会为此制作一个实用程序 class 和模块。类似于:

module DropdownExt

  def self.extended(receiver)
    receiver.each do |k,v|
      define_method(k) do 
        v.is_a?(Hash) ? v.extend(DropdownExt) : v
      end
    end
  end

end

class Dropdowns

  class << self

    private

    def dropdowns_spec
      YAML.load_file("#{path}").with_indifferent_access
    end

    def path
      Rails.root.join("spec/so/dropdowns/dropdowns.yaml") # <== you'll need to change this
    end

  end

  dropdowns_spec[:dropdown].each do |k,v|
    define_singleton_method k do 
      v.extend(DropdownExt)
    end
  end

  %i(
    truck_model
    bike_model
  ).each do |to_alias|
    singleton_class.send(:alias_method, to_alias, :car_model)
  end

end

然后你可以这样做:

Dropdowns.car_model
 => {"field1"=>{true=>"true", false=>"false"}, "region"=>{"US"=>"United States", "CA"=>"Canada"}}
Dropdowns.truck_model
 => {"field1"=>{"yes"=>"true", "no"=>"false"}, "region"=>{"US"=>"United States", "CA"=>"Canada"}}
Dropdowns.bike_model
 => {"field1"=>{"yes"=>"true", "no"=>"false"}, "region"=>{"US"=>"United States", "CA"=>"Canada"}}

随心所欲。

你会注意到我用自定义 DropdownExt 扩展了模型哈希,所以你也可以这样做:

Dropdowns.car_model.field1
 => {"yes"=>"true", "no"=>"false"}
Dropdowns.car_model.field1.yes 
 => "true"
Dropdowns.car_model.region.US
 => United States

当您对一个实例执行 extend(SomeModule) 时,只有该实例会使用模块进行扩展,因此您不会在整个应用程序中污染 Hash(在这种情况下)。

IMO,使用config似乎有点太低级了。但是,我意识到这是个人喜好的问题。此外,这将节省您的输入时间。

这种方法的另一个优点是您可以为每个模型 "for free" 获得 class 方法。所以你可以这样做:

Dropdowns.car_model

而不是

Rails.application.config.dropdown[:car_model]

我不知道。这对我来说似乎更好。

最后,我想我喜欢将整个东西封装在 class 中。同样,个人喜好问题。但是,这对我来说似乎更 ruby-ish。

顺便说一句,我的 YAML 想要将您的 yesno 更改为 truefalse。所以,我做了:

---
dropdown:
  car_model:
    field1:
      'yes':  'true'
      'no':   'false'
    region:
      US: United States
      CA: Canada

哪个返回

{"field1"=>{"yes"=>"true", "no"=>"false"}, "region"=>{"US"=>"United States", "CA"=>"Canada"}}