Rails Idioms + Django Templates + Erlang Power = Chicago BOSS

The Chicago Boss API is mostly stable, but still might change before 1.0.

Jump to: Generated instance methods   Associations (belongs_to, has)   Save hooks

BossRecords are specially compiled parameterized modules that follow the "active record" pattern. BossRecords go into your project's Model/ folder and will have functions generated for saving them into the database and for accessing related BossRecords. Important aspects of BossRecords:

  • The first parameter of a BossRecord should always be called Id, and the other parameters should be CamelCased attributes of your data model.

  • All parameters will be available as lower-case, underscored functions, e.g. -module(foo, [Id, TheText]) will generate the getter functions id() and the_text(), and the setters id(NewId) and the_text(NewText). Note that setters do not save the BossRecord.

  • To auto-generate an ID, pass the atom 'id' as the first parameter to my_module:new.

  • Call new with strings, floats, integers, atoms, or binaries for all other parameters

  • Parameters that end in "Time" (e.g., CreationTime, UpdateTime) should be passed either erlang:now() or a DateTime tuple.

  • You can add your own functions to a BossRecord module, which will have access to the generated functions described below.

  • To see the full API for a BossRecord called foo at any time during development, point your browser to /doc/foo on your dev server.

Generated functions

Generated instance functions of a BossRecord include:

save() -> {ok, SavedBossRecord} | {error, [ErrorMessages]}

Saves this boss_record record to the database. The returned record will have an auto-generated ID if the record's ID was set to 'id'. Performs validation first, returning ErrorMessages if validation fails. See validate/0.

validate() -> ok | {error, [ErrorMessages]}

Validates this boss_record without saving to the database. Errors are generated from this model's validation_tests/0 function (if defined), which should return a list of {TestFunction, ErrorMessage} tuples. For each test, TestFunction should be a fun of arity 0 that returns true if the record is valid or false if it is invalid. ErrorMessage should be a (constant) string that will be included in ErrorMessages if the associated TestFunction returns false on this particular boss_record.

attributes(Proplist) -> BossRecord

Set multiple record attributes at once. Does not save the record.

attributes() -> [{Key::atom(), Value::string() | undefined}]

A proplist of the boss_record parameters and their values.

attribute_names() -> [::atom()]

A list of the lower-case boss_record parameters.

reset(Counter::atom()) -> ok | {error, Reason}

Reset a counter to zero

incr(Counter::atom()) -> ::integer()

Atomically increment a counter by 1.

incr(Counter::atom(), Increment::integer()) -> ::integer()

Atomically increment a counter by the specified increment

belongs_to_names() -> [{::atom()}]

Retrieve a list of the names of belongs_to associations.

belongs_to() -> [{::atom(), BossRecord}]

Retrieve all of the belongs_to associations at once.

id() -> Id

Returns the value of Id

id(Id::string()) -> BossRecord

Set the value of Id.

Other getters and setters are generated based on the parameters of your BossRecord.

Associations

Special associations are generated from the following module attributes:

-belongs_to(foo).

Requires a matching FooId in the parameter list. Adds a function foo() which returns the BossRecord (of any type, usually foo) with ID equal to the current BossRecord's FooId.

-has({bar, 1}).
-has({bars, Count}). % Count > 1
-has({bars, many}). % alias for 1 million

Generates a function bar() or bars() which returns up to Count "bar" BossRecords with FooId equal to this BossRecord's ID. If Count is greater than 1, also creates first_bar() and last_bar() which return the first and last items in the association.

When Count is not equal to 1, has can also take a proplist of options as the third element in the tuple:

-has({bars, many, [{sort_by, first_name}]}).

Valid options are:

  • sort_by - attribute to sort on. Defaults to 'id'
  • sort_order - whether to sort numerically or as a string, and ascending or descending. Valid values are:
    • str_ascending - As string in dictionary order A-Z
    • str_descending - As string in reverse dictionary order Z-A
    • num_ascending - As number, low numbers first
    • num_descending - As number, high numbers first
  • module - If the assocation name is different than the underlying module, use this option to specify the underlying module.
  • foreign_key - If the associated module uses something unexpected for the foreign key, use this option to specify the foreign key (e.g. person_id).

Note that Time and float attributes are stored internally as integers, so sort them with num_ascending or num_descending.

The two above attributes work similar to belongs_to and has_many/has_one in Rails.

-counter(foo_counter).

Generates a function foo_counter() which returns the value of the counter, initialized to zero. Each BossRecord may have an unlimited number of counters. Manipulate the counters with reset and incr above.

SPECIAL NOTE: Everything in the Model directory will be compiled as a BossRecord rather than as a regular Erlang module; you don't need to do or declare anything special.

Save hooks

You can specify logic to be run anytime a BossRecord is saved. Just define one or more of these functions in your module:

  • before_create() - executed just before a new BossRecord is saved to the database.
  • before_update() - executed just before an existing BossRecord is saved to the database.
  • after_create() - executed just after a new BossRecord is saved to the database.
  • after_update() - executed just after an existing BossRecord is saved to the database.

Return values are ignored.