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?,fetchmethods
Installation & Setup
# Gemfile
gem "db_config"bundle installrails generate db_config:installrails db:migrateAvo 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_configUsage
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 setException 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"
endManaging 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 loadingTip
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) || 25Writing 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) # => nilDBConfig.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
ArgumentErrorwith 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 typeRaises:
-
DBConfig::NotFoundErrorif key doesn't exist -
ArgumentErrorfor 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.