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.
- 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
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-model# 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 relationship- 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
enddynamic-db-explorer \
--username root \
--adapter postgresql \
--database your_database \
--password your_password \
--create-class-files /path/to/modelsDynamic 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
enddb = DynamicActiveModel::Database.new(DB, database_config)
db.skip_table 'temporary_data'
db.skip_table /^temp_/
db.skip_tables ['old_data', /^backup_/]
db.create_models!db = DynamicActiveModel::Database.new(DB, database_config)
db.include_table 'users'
db.include_table /^customer_/
db.include_tables ['orders', 'products']
db.create_models!db.update_model(:users) do
attr_accessor :temp_password
def full_name
"#{first_name} #{last_name}"
end
end# 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')db.update_all_models('lib/db')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
}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 rubocopBug reports and pull requests are welcome on GitHub at https://github.com/dougyouch/dynamic-active-model.
The gem is available as open source under the terms of the MIT License.