Marten projects can be organized into logical and reusable components called "applications". These applications can contribute specific behaviors and abstractions to a project, including models, handlers, schemas, emails, and templates. They can be packaged and reused across various projects as well.
A Marten application is a set of abstractions (defined under a dedicated and unique folder) that provides some set of features. These abstractions can correspond to models, handlers, templates, schemas, emails, etc.
Marten projects always use one or many applications. Indeed, each Marten project comes with a default main application that corresponds to the standard
src folder: models, migrations, or other classes defined in this folder are associated with the main application by default (unless they are part of another explicitly defined application). As projects grow in size and scope, it is generally encouraged to start thinking in terms of applications and how to split models, handlers, or features across multiple apps depending on their intended responsibilities.
Another benefit of applications is that they can be packaged and reused across multiple projects. This allows third-party libraries and shards to easily contribute models, migrations, handlers, or templates to other projects.
The use of applications must be manually enabled within projects: this is done through the use of the
This setting corresponds to an array of installed app classes. Indeed, each Marten application must define a subclass of
Marten::App to specify a few things such as the application label (see Creating applications for more information about this). When those subclasses are specified in the
installed_apps setting, the applications' models, migrations, assets, and templates will be made available to the considered project.
Marten.configure do |config|
config.installed_apps = [
Adding an application class inside this array will have the following impact on the considered project:
- the models of this application and the associated migrations will be used
- the templates of the application will be made available to the templates engine
- the assets of the application will be made available to the assets engine
- the management commands defined by the application will be made available to the Marten CLI
The main application
The "main" application is a default application that is always implicitly used by Marten projects (which means that it does not appear in the
installed_apps setting). This application is associated with the standard
src folder: this means that models, migrations, assets, or templates defined in this folder will be associated with the main application by default. For example, models defined under a
src/models folder would be associated with the main application.
The main application is associated with the
main label. This means that models of the main application that do not define an explicit table name will have table names starting with
It should be noted that it is possible to create explicitly defined applications whose structures live under the
src folder as well: the abstractions (eg. models, migrations, etc) of these applications will be associated with them and not with the main application. This is because abstractions are always associated with the closest application in the files/folders structure.
In the end, the main application provides a convenient way for starting projects and prototyping without requiring to spec out how projects will be organized in terms of applications upfront. That being said, as projects grow in size and scope, it is really encouraged to start thinking in terms of applications and how to split abstractions and features across multiple apps depending on their intended responsibilities.
Order of installed applications
You should note that the order in which installed applications are defined in the
installed_apps setting can actually matter.
For example, a "foo" app might define a
test.html template, and a similar template with the exact same name might be defined by a "bar" app. If the "foo" app appears before the "bar" app in the array of installed apps, then requesting and rendering the
test.html template will actually involve the "foo" app's template only. This is because template loaders associated with app directories iterate over applications in the order in which they are defined in the installed apps array.
This is why it is always important to namespace abstractions, assets, templates, and locales when creating applications. Failing to do so exposes apps to conflicts with other applications' code. As such, in the previous example, the "foo" app should've defined a
foo/test.html template while the "bar" app should've defined a
bar/test.html template to avoid possible conflicts.
Creating applications can be done very easily through the use of the
app generator. For example:
marten gen app blog
Running such a command will add a new
blog application to the current project with the following structure:
These files and folders are described below:
|Empty directory where the emails of the application will be defined.
|Empty directory where the request handlers of the application will be defined.
|Empty directory that will store the migrations that will be generated for the models of the application.
|Empty directory where the models of the application will be defined.
|Empty directory where the schemas of the application will be defined.
|Empty directory where the templates of the application will be defined.
|Definition of the application configuration abstraction; this is also where application-specific file requirements should be made.
|Requirements of CLI-related files, such as migrations for example.
|Module containing the routes of the application.
app generator automatically ensures that:
- The newly created application is added to the
- Requirements for the application itself are added to the
- The application's routes are included in the main routes map (which lives in the
The most important file of an application is the
app.cr one. This file usually includes all the app requirements and defines the application configuration class itself, which must be a subclass of the
Marten::App abstract class. This class allows mainly to define the "label" identifier of the application (through the use of the
#label class method): this identifier must be unique across all the installed applications of a project and is used to generate things like model table names or migration classes.
Here is an example
app.cr file content for a hypothetic "blog" app:
class App < Marten::App
app.cr file is located is important: the directory where this file is defined is also the directory where key folders like
templates, etc, must be present. This is necessary to ensure that these files and abstractions are associated with the considered app.
Another very important file is the
cli.cr one: this file is there to define all the CLI-related requirements and will usually be required directly by your project's
manage.cr file. A minima the
cli.cr file should require model migrations, but it could also require the management commands provided by the application. For example:
Defining settings for applications
Applications that you create as part of your projects or third-party libraries can have their own associated settings, configurable through the use of regular settings files.
In order to define settings for your applications, the simplest way is to create a
settings.cr file containing a subclass of
Marten::Conf::Settings in your application's folder. This subclass must make use of the
#namespace macro in order to define the setting "namespace" under which your application's settings will be accessible.
class Settings < Marten::Conf::Settings
@my_setting : String = "foo"
With the above example, it will be possible to configure the
blog.my_setting setting as follows in a project's settings file:
Marten.configure do |config|
config.blog.my_setting = "bar"
As you can see, the application's settings are configurable like any other built-in settings, but they are namespaced to the namespace value that was defined in the
Blog::Settings class through the use of the
It's important to note that
Marten::Conf::Settings subclasses have the flexibility to define any necessary methods to facilitate user configuration for the considered application. While basic settings typically necessitate only getters and setters for configuration, more intricate scenarios may demand additional methods, the utilization of blocks, or other complexities.