Project

db_config

0.0
The project is in a healthy, maintained state
DBConfig provides a powerful, database-backed configuration store for Rails applications. Store and retrieve configuration values dynamically with automatic type detection and conversion (strings, integers, floats, booleans, arrays, hashes, and nil). Features eager loading for high-performance access to frequently used configs, a simple API (get/set/update/delete), and seamless integration with Avo admin panels. See https://github.com/avo-hq/db_config for full documentation and usage examples.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
2025
2026
 Dependencies

Runtime

 Project Readme

DBConfig

Database-backed configuration store for Rails with automatic type conversion, default values, and high-performance eager loading.

Features

  • Type-safe storage: Auto-detects and converts strings, integers, floats, booleans, arrays, hashes, and nil

  • Eager loading: Cache frequently accessed configs for near-zero database overhead

  • Simple API: get/read, get!, set/write, update, delete, exist?, fetch methods

Installation & Setup

# Gemfile
gem "db_config"
bundle install
rails generate db_config:install
rails db:migrate

Avo Integration

Tip

If you're using Avo, this gem ships with a pre-configured resource out of the box that should be visible on the menu as "Configurations". If you're using Avo Pro with a custom menu, you can render the resource using:

resource :db_config

Usage

Set any data type - auto-detected and preserved

DBConfig.set(:max_users, 1000)
DBConfig.write(:site_title, "My App") # write is an alias for set
DBConfig.set(:enabled, true)
DBConfig.set(:rate, 0.05)
DBConfig.set(:tags, ["ruby", "rails"])
DBConfig.set(:config, {api: "https://api.example.com", timeout: 30})
DBConfig.set(:feature, nil)

Get with type preservation

DBConfig.get(:max_users)    # => 1000 (Integer)
DBConfig.read(:enabled)     # => true (Boolean) - alias for get

# Get missing config (safe - returns nil)
DBConfig.get(:missing_key)                # => nil

# Get missing config with get! (raises error)
DBConfig.get!(:missing_key)               # => raises DBConfig::NotFoundError

# Check if a config exists
DBConfig.exist?(:page_size)               # => true or false

# Fetch with block - stores block result if key doesn't exist
DBConfig.fetch(:page_size) { 25 }         # => 25 (stores if not found)

# Use || operator for fallback values
DBConfig.get(:page_size) || 25            # => 25 if :page_size not set

Exception Handling

# Strict get - raises exception if not found
begin
  value = DBConfig.get!(:api_token)
rescue DBConfig::NotFoundError => e
  Rails.logger.warn "Missing config: #{e.message}"
  value = "default_token"
end

Managing Configurations

# Update configurations with type safety
DBConfig.set(:max_users, 1000)                              # Set value and type to Integer
DBConfig.update(:max_users, value: 500)                     # Update value keeping same type

DBConfig.set(:site_enabled, "true")                         # Set value and type to String
DBConfig.update(:site_enabled, type: "Boolean")             # Convert "true" string to boolean true

DBConfig.set(:cache_ttl, 3600)                              # Set value and type to Integer
DBConfig.update(:cache_ttl, value: 4600, eager_load: true)  # Update value and enable eager loading

DBConfig.delete(:old_setting)                               # => true if deleted, false if not found

⚡ Eager Loading

Note

Eager loaded configs are cached per request and automatically synced when changed

# Mark configs for eager loading (loaded once per request, cached)
DBConfig.set(:api_key, "secret123")
DBConfig.update(:api_key, eager_load: true)   # Enable eager loading

# Now served from cache (no database query)
DBConfig.get(:api_key)                         # Served from cache

DBConfig.update(:api_key, eager_load: false)  # Disable eager loading

Tip

Good for: API keys, site settings, frequently accessed configs Avoid: Rarely used configs, large data, user-specific settings

Supported Types

Auto-detects and preserves: String, Integer, Float, Boolean, Array, Hash, nil

# All types preserved exactly
DBConfig.set(:string, "hello")           # => "hello" (String)
DBConfig.set(:integer, 42)               # => 42 (Integer)
DBConfig.set(:float, 3.14)               # => 3.14 (Float)
DBConfig.set(:boolean, true)             # => true (Boolean)
DBConfig.set(:array, [1, 2, 3])          # => [1, 2, 3] (Array)
DBConfig.set(:hash, {a: 1})              # => {a: 1} (Hash)
DBConfig.set(:null, nil)                 # => nil (NilClass)

API Reference

Reading Methods

Method Description Raises Errors Example
get(key) Safe retrieval, returns nil if not found No DBConfig.get(:api_key)
get!(key) Strict retrieval Yes, NotFoundError DBConfig.get!(:api_key)
read(key) Alias for get() No DBConfig.read(:api_key)
exist?(key) Check if key exists No DBConfig.exist?(:api_key)
fetch(key, &block) Get or store block result No DBConfig.fetch(:size) { 25 }

Fallback Pattern: Use the || operator to provide fallback values when keys don't exist:

# Recommended pattern for fallback values
page_size = DBConfig.get(:page_size) || 25

Writing Methods

Method Description Example
set(key, value) Store configuration DBConfig.set(:api_key, "secret")
write(key, value) Alias for set() DBConfig.write(:api_key, "secret")
update(key, **options) Update existing config DBConfig.update(:key, value: 42)
delete(key) Remove configuration DBConfig.delete(:old_key)

Method Details

DBConfig.fetch(key, &block)

Gets the value if it exists, or executes the block and stores the result if it doesn't.

# If key exists, returns existing value (block not executed)
DBConfig.set(:api_timeout, 30)
timeout = DBConfig.fetch(:api_timeout) { 60 }    # => 30 (existing value)

# If key doesn't exist, executes block and stores result
cache_size = DBConfig.fetch(:cache_size) { 100 } # => 100 (stores 100)
cache_size = DBConfig.fetch(:cache_size) { 200 } # => 100 (returns stored value)

# Works with any data type
features = DBConfig.fetch(:features) { ["feature1", "feature2"] }
config = DBConfig.fetch(:api_config) { {endpoint: "api.com", timeout: 30} }

# Returns nil if no block given and key doesn't exist
DBConfig.fetch(:missing_key)  # => nil

DBConfig.update(key, **options)

Updates configuration entry with intelligent type conversion and validation.

Parameters:

  • key (Symbol/String) - Configuration key (must exist)
  • **options - Keyword arguments for updates:
    • value: Any - New value to store (with type compatibility checking)
    • type: String - Target type for conversion ("String", "Integer", "Float", "Boolean", "Array", "Hash", "NilClass")
    • eager_load: Boolean - Enable/disable eager loading

Returns: The updated value in its final type

Type Compatibility:

  • When updating value: New values can change type automatically (e.g., "hello" → 42 changes String to Integer)
  • When updating type: Only compatible conversions are allowed (e.g., "123" → Integer, "hello" → Integer fails)
  • Incompatible type conversions raise ArgumentError with detailed message

Examples:

# Update value (can change type automatically)
DBConfig.set(:config_value, "hello")
DBConfig.update(:config_value, value: 42)    # String → Integer (automatic)

# Change type explicitly (requires compatibility)
DBConfig.set(:enabled, "true")              # "true" is set as a string
DBConfig.update(:enabled, type: "Boolean")  # "true" → true (compatible conversion)

# Update multiple attributes
DBConfig.update(:cache_size, value: 1000, eager_load: true)

# Examples from the specification
DBConfig.update(:key, eager_load: true)
DBConfig.update(:key, type: "Boolean")      # Only works if current value is compatible
DBConfig.update(:key, eager_load: true, value: true)  # ✅ Always works

# Fails only on incompatible TYPE conversions (not value updates)
DBConfig.set(:username, "admin")
DBConfig.update(:username, type: "Integer")  # ❌ Fails: "admin" can't become Integer
DBConfig.update(:username, value: 123)       # ✅ Works: new value can be any type

Raises:

  • DBConfig::NotFoundError if key doesn't exist
  • ArgumentError for invalid types or incompatible conversions

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/avo-hq/db_config.

License

The gem is available as open source under the terms of the MIT License.