Settei 設定用的GEM


#1

做了一個新的 gem ,是用來取代 settingslogic/figaro/dotenv 。

安裝以後,執行以下 rake task 作安裝:

$ rake settei:install:rails

使用方法

要是 config/environments/default.yml 內容是這樣:

the_answer_to_life_the_universe_and_everything: 42
google:
  api: foo

就能這樣取得設定

Setting.dig(:the_answer_to_life_the_universe_and_everything)
Setting.dig(:google, :api)

更詳盡的使用方法請閱讀 github

為何作這個 gem

我想要符合 12-factor app ,靠 env var 而不是複製設定檔案到遠端。但是我又很討厭 env var,命名這很麻煩,名字又很容易變很長。我喜歡 settingslogic 可以做到巢狀 hash。你們自己看看:

# 傳統使用 ENV 就得寫一長串超累:
BOARD_PAGINATION_PER_PAGE=5
BOARD_PAGINATION_MAX_PAGE=10
BOARD_REPLY_OMIT_CONDITION_N_RECENT_ONLY=5
BOARD_REPLY_OMIT_CONDITION_AVOID_ONLY_N_HIDDEN=2
# 使用YAML 就簡單很多,Settei就是因為這樣而使用 yaml
board:
  pagination:
    per_page: 5
    max_page: 10
  reply_omit_condition:
    n_recent_only: 5
    avoid_only_n_hidden: 2

設定一多,用 env var 就更不可能了。

Rails 的 secrets.yml 跟 credentials.yml 等等,我超級討厭的。把一件簡單的事情搞得超級複雜。

然後 settingslogic/figaro/dotenv 都很久沒更新了。

所以我自己照自己的需求,做了一個。這 gem 的重點就是,把設定檔案給 serialize,整個用 env var 送到遠端。這樣就不需要複製檔案,可以給 heroku 之類的 12-factor app 環境執行。然後還是能保留 yaml 的優勢。

歡迎指教~~


#2

我剛看了 env var … 那啥鬼東西||| 因為目前的系統是分散式的,一個 config 檔可能都破百行的 ||| 且這樣的命名規則中

root:
  one:
    two: 123
  one_two: 123

會碰撞哩,而目前專案最多的 config 最多的應該有到 150+ … 用 env var 一定會死掉,且全域污染的,類似有 lib 用了 ROOT_ONE_TWO 且包裝內無宣告或是宣告流程交錯時

我真正使用時只用了類似 $configure 這變數而已(Hash , 你可以自己取,其實就是 YAML.load)然後結構就同 YAML,定時還可以和 DB 對照更新,甚至也可以回存 YAML,概念基本上和你完全一樣就是

不過看你的實作很複雜?對我而言應該只要保證是 design pattern 中的 singleton 就好了哩,其餘實作應該應該不是那麼重要才是?而 Ruby 內做 singleton 最簡單應該是提成 class variable,如果還要 thread safe 的話應該也只要 mutex ( semaphore ) 就能結束了|||,為何要加那麼多其餘的東西?


#3

抱歉,我readme可能沒寫好,你舉的例子跟這個gem的用法完全相反。

只有在 deploy 時,才會使用 env var,而且只會使用一個,傳的是 serialized 的 YAML 檔案。

而在 rails 本身,取得設定就是使用 Setting.dig(:root, :one, :two)

這樣懂嗎?可以建議一下readme要怎樣改比較好懂哈哈


#4

發覺我也沒回好||| 其實我想有把兩件事情拆開回應就是了,不過我的思維會類似你 readme 內寫的

If you don't care about 12-factor app, you can roll your own solution to just copy the yml file to production

另外一方面會建議你 kiss 原則,把這 gem 打到最簡單,包括 readme,只針對你想解決 / 取得 setting 值這件事情即可,其餘的都在最下面用補述的方式來完成(不然目前看起來混在一起了…),且 extension 之類的可以用另外一個 gem 來補充?


#5

我想解決的問題是 deploy 也符合 12-factor 的 YAML config 方案。
所以這已經是最簡單的了。
實際上就兩個 class 跟 deploy 設定,不到兩百行。
下面的是給有需要客製化的人的文件。


#6

我自己的解法是

config/application.rb:

module TheApp
  class Application < Rails::Application
    # Settings in config/environments/* take precedence over those specified here.
    # Application configuration should go into files in config/initializers
    # -- all .rb files in that directory are automatically loaded.
    # Application configuration can also go into config/configurations.yml
    # -- these configs will load into config.configurations
    $configurations = config.configurations =
        config_for(:configurations).nested_under_indifferent_access

    # ...
  end
end

config/configurations.yml:

default: &default
  application:
    host: <%= ENV['APP_HOST'] || 'app.test' %>
  oauth:
    google:
      url: <%= ENV['OAUTH_GOOGLE_URL'] %>
      token: <%= ENV['OAUTH_GOOGLE_TOKEN'] %>
  recaptcha:
    secret: <%= ENV['RECAPTCHA_SECRET'] %>
  jwt:
    algorithm: <%= ENV['JWT_ALGORITHM'] || 'HS512' %>
    secret: <%= ENV['JWT_SECRET'] %>

development:
  <<: *default

production:
  <<: *default

test:
  <<: *default

至於 ENV 要怎麼給可以自由使用 dotenv 之類的 gem,或是照樣給 env var

使用的時候就直接 $configurations.dig(:oauth, :google, :token) 或是 Rails.configuration.configurations.dig(:oauth, :google, :token)


#7

@david50407

你的 configurations.yml 有進入 git 嗎?


#8

當然有進啊,沒進去管理的是環境變數
這個檔案就是在建立環境變數跟預設值還有與 $configurations 的關聯,我覺得這樣就很足夠了啊 不需要額外的gem…


#9

嘛 … 他的意思是就是不希望一票 ENV & 裡面有把 yaml 用 zlib 壓縮的字段,來當類似 yaml => hash 的方式用哩,& 他的方式其實是個好點子就是,要達到相同方式你開心也可以用單一 ENV 然後接 base64 + [ marshal or yaml ] 也行?單純過 zlib 後會小很多之類的 (( 當然剩下就是你要處理 binary 的問題了|||


#10

只是覺得如果你要加一個設定,你必須

  1. 想一個在 yaml 上的名字
  2. 想一個在 ENV 的名字
  3. 嘗試把 ENV 設定設在遠端機器

Settei 只需要

  1. 想一個在 yaml 上的名字
  2. deploy

就好了