Rss

KvaziBlog.com *

Me on GitHub / LinkedIn

Use Yaml-files for Storing Project Settings

Recently I was solving one issue with storing settings in yaml file at the project I'm working on right now. The trick was also to give users certain permissions what keys are allowed to be edited. Well, it's now done and I'm happy to share with the solution I came up with. At the end I had to stick the information about the access level to each key that we are storing. The example of such a yaml-file with settings can look like this:

---
api_url:
  value: example.com/api
  role: 4
api_login:
  value: user
  role: 4
api_password:
  value: 12355
  role: 4

In this case, we have three variables where we store the url, login and password to a certain API. Each key represented as a hash for storing a value and the minimum role that the user should have in order to access the data. Now, let's have a look on the code of the class that will have all the logic described above and will handle that yaml file:

require 'yaml'

class Setting

  CONFIG_FILE = 'settings.yml'

  class << self

    def get(key)
      load_settings[key.to_s]['value']
    end

    def update(params, role)
      settings = load_settings
      params.each do |key, value|
        key = key.to_s
        settings[key]['value'] = value.to_s if has_access?(role, key)
      end
      save_settings(settings)
    end

    def has_access?(role, key)
      return unless setting = load_settings[key]
      role >= setting['role']
    end

    def load_settings
      @config ||= YAML.load(File.read(file_path))
    end

    private

    def save_settings(settings)
      File.write(file_path, settings.to_yaml)
    end

    def file_path
      "config/#{CONFIG_FILE}"
    end

  end

end

If anywhere in your app you want to get a value of a certain key, you can do it like this:

Setting.get('api_login')
Setting.get('api_password')
…

When you update any settings the permission check will be done in the class automatically so you don't have to care about this anymore. You can simply pass a hash with all the params that user input and only those will be updated that current user has access to. That allows you to pass params like this:

Setting.update(params[:settings], current_user.role)

Here we are passing the information that should be updated and the current user role. The method that stores the path to a file with settings can be set in a nicer way if you use Rails:

Rails.root.join('config', CONFIG_FILE)