Dynamic Active Model
A Ruby gem that automatically discovers your database schema and creates corresponding ActiveRecord models with proper relationships. Perfect for rapid prototyping, database exploration, and working with legacy databases.
Features
- Automatic Schema Discovery: Introspect database tables without manual configuration
- Dynamic Model Creation: Generate ActiveRecord models at runtime
-
Relationship Mapping: Automatic
has_many,belongs_to,has_one, andhas_and_belongs_to_manydetection -
Model Extensions: Customize models with
.ext.rbfiles - Table Filtering: Blacklist or whitelist tables using strings or regex patterns
- Dangerous Attribute Protection: Safe handling of column names that conflict with Ruby methods
-
Unique Constraint Detection: Automatically uses
has_onewhen foreign keys have unique indexes - Join Table Detection: Recognizes HABTM join tables (two FK columns, no primary key)
- Model File Generation: Export discovered models to static Ruby files
-
CLI Tool: Interactive database exploration via
dynamic-db-explorer
Installation
Add this line to your application's Gemfile:
gem 'dynamic-active-model'And then execute:
$ bundle installOr install it yourself as:
$ gem install dynamic-active-modelQuick Start
In-Memory Model Creation
# Define your database model namespace
module DB; end
# Create models and relationships in one step
DynamicActiveModel::Explorer.explore(DB,
username: 'root',
adapter: 'postgresql',
database: 'your_database',
password: 'your_password'
)
# Start using your models
movie = DB::Movie.first
movie.name
movie.actors # Automatically mapped relationshipUsing in a Rails Application
- Configure Rails to handle the
DBnamespace correctly inconfig/initializers/inflections.rb:
ActiveSupport::Inflector.inflections do |inflect|
inflect.acronym 'DB'
end- Ignore the DB namespace for eager loading in
config/application.rb:
module YourApp
class Application < Rails::Application
Rails.autoloaders.main.ignore(
"#{config.root}/app/models/db"
)
end
end- Create a base module file in
app/models/db.rb:
module DB
include DynamicActiveModel::Setup
# Use the primary database connection from database.yml
connection_options 'primary'
# Set the path for auto-loading extension files
extensions_path 'app/models/db'
# Optionally skip tables you don't want to model
skip_tables ['schema_migrations', 'ar_internal_metadata']
# Create all models
create_models!
end- Extend specific models with
.ext.rbfiles inapp/models/db/:
# app/models/db/users.ext.rb
update_model do
def full_name
"#{first_name} #{last_name}"
end
def active?
status == 'active'
end
endNote: Extension files are based on the table name, not the model name. For a table named
user_profiles, useuser_profiles.ext.rb.
- Use your models throughout the Rails application:
class UsersController < ApplicationController
def show
@user = DB::User.find(params[:id])
@full_name = @user.full_name
end
endGenerate Model Files
dynamic-db-explorer \
--username root \
--adapter postgresql \
--database your_database \
--password your_password \
--create-class-files /path/to/modelsAdvanced Usage
Relationship Types
Dynamic Active Model automatically detects and creates four types of relationships:
| Relationship | Detection |
|---|---|
belongs_to |
Foreign key column exists |
has_many |
Another table references this table |
has_one |
Foreign key has a unique constraint |
has_and_belongs_to_many |
Join table with exactly two FK columns and no primary key |
Example join table detection:
# Table: actors_movies (join table)
# - actor_id (foreign key to actors.id)
# - movie_id (foreign key to movies.id)
# - No primary key
# Results in:
class Actor < ActiveRecord::Base
has_and_belongs_to_many :movies
end
class Movie < ActiveRecord::Base
has_and_belongs_to_many :actors
endTable Filtering
Blacklist Tables
db = DynamicActiveModel::Database.new(DB, database_config)
db.skip_table 'temporary_data'
db.skip_table /^temp_/
db.skip_tables ['old_data', /^backup_/]
db.create_models!Whitelist Tables
db = DynamicActiveModel::Database.new(DB, database_config)
db.include_table 'users'
db.include_table /^customer_/
db.include_tables ['orders', 'products']
db.create_models!Extending Models
Inline Extensions
db.update_model(:users) do
attr_accessor :temp_password
def full_name
"#{first_name} #{last_name}"
end
endFile-based Extensions
# lib/db/users.ext.rb
update_model do
attr_accessor :temp_password
def full_name
"#{first_name} #{last_name}"
end
end
# Apply the extension
db.update_model(:users, 'lib/db/users.ext.rb')Mass Update All Models
db.update_all_models('lib/db')Database Connection
The gem supports all ActiveRecord database adapters:
{
adapter: 'postgresql', # or 'mysql2', 'sqlite3', etc.
host: 'localhost',
database: 'your_database',
username: 'your_username',
password: 'your_password',
port: 5432
}Documentation
Development
After checking out the repo, run bundle install to install dependencies. Then, run bundle exec rspec to run the tests.
bundle install
bundle exec rspec
bundle exec rubocopContributing
Bug reports and pull requests are welcome on GitHub at https://github.com/dougyouch/dynamic-active-model.
License
The gem is available as open source under the terms of the MIT License.