Modelist
CLI and API to test and analyze ActiveRecord models.
Setup
In your Rails 3+ project, add this to your Gemfile:
gem 'modelist'
Then run:
bundle install
API Configuration
Not needed for CLI. Just used if you are using as an API:
Modelist::quiet = true
Usage
CLI
Modelist has a command-line interface with options to test for required circular dependencies, models that the specified models require due to nullable or validation constraints, or to test attributes and associations.
Circular
Check ActiveRecord circular dependencies. Find circular chains of dependencies where foreign keys that are not primary keys of the models are all not nullable in the schema or not nullable because of ActiveRecord presence validation with:
bundle exec modelist circular
or:
bundle exec modelist circular my_model_1 my_model_2 --output-file=/path/to/errors.log
Example output:
The following non-nullable foreign keys used in ActiveRecord model associations are involved in circular dependencies:
beers.waitress_id -> waitresses.bartender_id -> bartenders.beer_id -> beers.waitress_id
beers.waitress_id -> waitresses.bartender_id -> bartenders.order_id -> order.beer_id -> beers.waitress_id
Distinct foreign keys involved in a circular dependency:
beers.waitress_id
order.beer_id
bartenders.beer_id
bartenders.order_id
waitresses.bartender_id
Foreign keys by number of circular dependency chains involved with:
2 (out of 2): beers.waitress_id -> waitresses
2 (out of 2): waitresses.bartender_id -> bartenders
1 (out of 2): order.beer_id -> beers
1 (out of 2): bartenders.order_id -> order
1 (out of 2): bartenders.beer_id -> beers
Specify --output-file to provide an pathname of an errors file.
Required
Find the models that the specified models have non-nullable or presence validations for directly and indirectly. You can use this to determine which models are really required with:
bundle exec modelist required my_model_1 my_model_2
Example output:
Required models:
Bartender
Beer
Order
Waitress
Test
Test ActiveRecord models, their attributes, and associations with:
bundle exec modelist test
or:
bundle exec modelist test my_model_1 my_model_2 --output-file=/path/to/errors.log
Example output:
(...example data from models and attributes...)
---
FAILED: MyModel
---
MyModel.last.some_associations: PG::Error: ERROR: operator does not exist: character varying = integer
LINE 1: ...oobars" WHERE "foobars"."my_model_id" = 7
^
(...continued and backtrace...)
---
(...more errors...)
Passed (258):
---
AnotherGoodModel
GoodModel
...
Warnings (123):
---
Foo.first was nil. Assuming there is no data in the associated table, but please verify.
Bar's belongs_to :waitresses may need to be singularized to waitress?
...
Failed (85):
---
Bar
Foobar
MyModel
Specify --output-file to provide an pathname of an errors file.
Search
Given a (partial) model/tablename/column/association name, finds all matching models/associations:
bundle exec modelist search partial_search_string
Example output:
Models:
Foo (table: foos)
Foobar (table: foobars)
Associations:
Bar (table: bars), association: foo (macro: belongs_to, options: {})
Loo (table: loos), association: f_users (macro: has_one, options: {:foreign_key=>:foo_id})
Path Finder
Given two model names will find known paths:
bundle exec modelist paths my_model_1 my_model_2
Example output:
checking for path from foobar to barfoo...
+++++++-+-++--+------
Paths from foobar to barfoo (2):
foobar.foo -> foo.barfoos -> barfoo
foobar.barfoo -> barfoo
API
Modelist::Analyst.find_required_models(:model1, :model2)
Modelist::CircularRefChecker.test_models(:model1, :model2, output_file: true)
Modelist::Tester.test_models(:model1, :model2, output_file: true)
Modelist::Searcher.find_all('foo')
Modelist::PathFinder.find_all(:model1, :model2)
License
Copyright (c) 2012-2013 Gary S. Weaver, released under the MIT license.