---
title: Marten 0.5.0 release notes
pagination_prev: null
pagination_next: null
---

_July 13, 2024._

## Requirements and compatibility

* **Crystal:** 1.11, 1.12, and 1.13.
* **Databases:**
  * MariaDB 10.4 and higher.
  * MySQL 8.0.11 and higher.
  * PostgreSQL 12 and higher.
  * SQLite 3.27.0 and higher.

## New features

### Relations pre-fetching

Marten now provides the ability to prefetch relations when using [query sets](../../models-and-databases/queries.md) through the use of the new [`#prefetch`](../../models-and-databases/reference/query-set.md#prefetch) method. When using [`#prefetch`](../../models-and-databases/reference/query-set.md#prefetch), the records corresponding to the specified relationships will be prefetched in single batches and each record returned by the original query set will have the corresponding related objects already selected and populated.

For example:

```crystal
posts_1 = Post.all.to_a
# hits the database to retrieve the related "tags" (many-to-many relation)
puts posts_1[0].tags.to_a

posts_2 = Post.all.prefetch(:tags).to_a
# doesn't hit the database since the related "tags" relation was already prefetched
puts posts_2[0].tags.to_a
```

Like the existing [`#join`](../../models-and-databases/reference/query-set.md#join) method, this allows to alleviate N+1 issues commonly encountered when accessing related objects. However, unlike [`#join`](../../models-and-databases/reference/query-set.md#join) (which can only be used with single-valued relationships), [`#prefetch`](../../models-and-databases/reference/query-set.md#prefetch) can be used with both single-valued relationships and multi-valued relationships (such as [many-to-many](../../models-and-databases/relationships.md#many-to-many-relationships) relationships, [reverse many-to-many](../../models-and-databases/relationships.md#backward-relations-2) relationships, and [reverse many-to-one](../../models-and-databases/relationships.md#backward-relations) relationships).

Please refer to [Pre-fetching relations](../../models-and-databases/queries.md#pre-fetching-relations) to learn more about this new capability.

### Model scopes

It is now possible to define [scopes](../../models-and-databases/queries.md#scopes) in model classes. Scopes allow to pre-define specific filtered query sets, which can be easily applied to model classes and model query sets.

Such scopes can be defined through the use of the [`#scope`](pathname:///api/0.5/Marten/DB/Model/Querying.html#scope(name%2C%26block)-macro) macro, which expects a scope name (string literal or symbol) as first argument and requires a block where the query set filtering logic is defined:

```crystal
class Post < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :title, :string, max_size: 255
  field :is_published, :bool, default: false
  field :created_at, :date_time

  // highlight-next-line
  scope :published { filter(is_published: true) }
  // highlight-next-line
  scope :unpublished { filter(is_published: false) }
  // highlight-next-line
  scope :recent { filter(created_at__gt: 1.year.ago) }
end

Post.published # => Post::QuerySet [...]>
```

It is also possible to override the default scope through the use of the [`#default_scope`](pathname:///api/0.5/Marten/DB/Model/Querying.html#default_scope-macro) macro. This macro requires a block where the query set filtering logic is defined:

```crystal
class Post < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :title, :string, max_size: 255
  field :is_published, :bool, default: false
  field :created_at, :date_time

  // highlight-next-line
  default_scope { filter(is_published: true) }
end
```

Please refer to [Scopes](../../models-and-databases/queries.md#scopes) for more details on how to define scopes.

### Enum field for models and schemas

It is now possible to define `enum` fields in [models](../../models-and-databases/reference/fields.md#enum) and [schemas](../../schemas/reference/fields.md#enum). For models, such fields allow you to store valid enum values, with validation enforced at the database level. When validating data with schemas, they allow you to expect valid string values that match those of the configured enum.

For example:

```crystal
enum Category
  NEWS
  BLOG
end

class Article < Marten::Model
  field :id, :big_int, primary_key: true, auto: true
  field :category, :enum, values: Category
end

article = Article.last!
article.category # => Category::BLOG
```

### Raw SQL predicate filtering

Marten now provides the ability to filter [query sets](../../models-and-databases/queries.md) using [raw SQL predicates](../../models-and-databases/raw-sql.md#filtering-with-raw-sql-predicates) through the use of the `#filter` method. This is useful when you want to leverage the flexibility of SQL for specific conditions, but still want Marten to handle the column selection and query building for the rest of the query.

For example:

```crystal
Author.filter("first_name = :first_name", first_name: "John")
Author.filter("first_name = ?", "John")
Author.filter { q("first_name = :first_name", first_name: "John") }
```

Please refer to [Filtering with raw SQL predicates](../../models-and-databases/raw-sql.md#filtering-with-raw-sql-predicates) to learn more about this new capability.

### Minor features

#### Models and databases

* A new [`#pks`](../../models-and-databases/reference/query-set.md#pks) method was introduced for query sets to make it easy to retrieve the primary key values of the model records targeted by a given current query set.
* A [`#count`](pathname:///api/0.5/Marten/DB/Model/Querying/ClassMethods.html#count(field%3AString|Symbol|Nil%3Dnil)-instance-method) method is now available on model classes and provides the same functionality as the [`#count`](../../models-and-databases/reference/query-set.md#count) query set method.
* A new [`#bulk_create`](../../models-and-databases/reference/query-set.md#bulk_create) method was introduced to make it easy to insert multiple model instances into the database in a single query (which can be useful when dealing with large amounts of data that need to be inserted into the database).
* A new [`#average`](../../models-and-databases/reference/query-set.md#average) method was introduced to allow computing the average values of a specific model field at the database level for the records targeted by a specific query set.
* A new [`#sum`](../../models-and-databases/reference/query-set.md#sum) method was introduced to allow computing the sum of the values of a specific model field at the database level for the records targeted by a specific query set.
* It is now possible to compute the minimum and maximum values of a specific field at the database level for the records targeted by a query set through the use of the [`#minimum`](../../models-and-databases/reference/query-set.md#minimum) and [`#maximum`](../../models-and-databases/reference/query-set.md#maximum) methods.
* The [`in`](../../models-and-databases/reference/query-set.md#in) query set predicate now supports filtering on arrays of model records directly.
* Query sets now provide a [`#to_sql`](../../models-and-databases/reference/query-set.md#to_sql) method allowing to retrieve the corresponding SQL representation.
* Query sets can now be combined using the AND and OR binary operators. This can be achieved through the use of the [&](../../models-and-databases/reference/query-set.md#-and) and [`|`](../../models-and-databases/reference/query-set.md#-or) query set methods.
* Invalid record exceptions (instances of [`Marten::DB::Errors::InvalidRecord`](pathname:///api/0.5/Marten/DB/Errors/InvalidRecord.html)) now provide more details regarding the actual errors of the associated record.
* Creations of records from many-to-one reverse relation query sets are now scoped to the related record. See [Many-to-one relationships](../../models-and-databases/relationships.md#many-to-one-relationships) for more details.
* A new [`#build`](../../models-and-databases/reference/query-set.md#build) method was introduced to make it possible to initialize new model instances from query sets.

#### Handlers and HTTP

* The [`#render`](../../handlers-and-http/introduction.md#render) helper method and the generic handlers that involve template renderings now automatically insert the request object in the template context.
* The [`Marten::Handlers::RecordDetail`](../../handlers-and-http/reference/generic-handlers.md#displaying-a-record), [`Marten::Handlers::RecordUpdate`](../../handlers-and-http/reference/generic-handlers.md#updating-a-record), and [`Marten::Handlers::RecordDelete`](../../handlers-and-http/reference/generic-handlers.md#deleting-a-record) generic handlers now provide the ability to specify a custom [query set](../../models-and-databases/queries.md) instead of a model class. This can be achieved through the use of the [`#queryset`](pathname:///api/0.5/Marten/Handlers/RecordRetrieving.html#queryset(queryset)-macro) macro.
* A new middleware was introduced to make it easy to override the method of incoming requests based on the value of a specific request parameter or header: the [method override middleware](../../handlers-and-http/reference/middlewares.md#method-override-middleware). This mechanism is useful for overriding HTTP methods in HTML forms that natively support GET and POST methods only. A dedicated set of [settings](../../development/reference/settings.md#method-overriding-settings) is also available to easily customize the behavior of this middleware.
* The value of the max-age directive used for the Cache-Control header that is set by the [assets serving middleware](../../handlers-and-http/reference/middlewares.md#asset-serving-middleware) can now be configured in the [`assets.max_age`](../../development/reference/settings.md#max_age) setting.
* Subclasses of the [`Marten::Handlers::Template`](../../handlers-and-http/reference/generic-handlers.md#rendering-a-template) generic handler now support a [`#content_type`](pathname:///api/0.5/Marten/Handlers/Rendering/ClassMethods.html#content_type(content_type%3AString|Nil)-instance-method) class method that allows configuring the content type of the response (unless specified, the content type will default to `text/html`).

#### Templates

* Enum values can now be used in templates. Please refer to [Using enums in contexts](../../templates/introduction.md#using-enums-in-contexts) to learn more about this capability.
* Support for the `nil`, `true`, and `false` literals was added to the Marten templating language. Please refer to [Literal values](../../templates/introduction.md#literal-values) for more details on supported literals.
* The [`assign`](../../templates/reference/tags.md#assign) template tag now supports an `unless assigned` suffix which allows to specify that the assignment must happen only if no variable with the same name is already present in the template context.
* The [`include`](../../templates/reference/tags.md#include) template tag now supports `isolated` and `contextual` suffixes that allow specifying whether the included templates should have access to the outer context variables. Unless specified, the default behavior is controlled by the new [`templates.isolated_inclusions`](../../development/reference/settings.md#isolated_inclusions) setting.
* A new [`capture`](../../templates/reference/tags.md#capture) template tag was introduced to make it possible to easily assign the output of a block of code to a new variable.
* The output of the [`csrf_token`](../../templates/reference/tags.md#csrf_token) template tag can now be outputted to a variable by leveraging the `as` keyword.
* The `loop` variable, which is available when using the [`for`](../../templates/reference/tags.md#for) template tag, now supports `even?` and `odd?` attributes.
* A new [`csrf_input`](../../templates/reference/tags.md#csrf_input) template tag was introduced to make it easier to insert the CSRF token into HTML forms. This new tag allows the generation of a hidden form input containing the CSRF token computed for the current request.
* A new [`escape`](../../templates/reference/tags.md#escape) template tag was introduced to allow disabling/enabling [auto-escaping](../../templates/introduction.md#auto-escaping) within a block.
* A new [`unless`](../../templates/reference/tags.md#unless) template tag was introduced to provide an alternative way of writing conditional template blocks.

#### Development

* The [`collectassets`](../../development/reference/management-commands.md#collectassets) management command now provides the ability to fingerprint collected assets and generate a corresponding JSON manifest. Please refer to [Asset manifests and fingerprinting](../../assets/introduction.md#asset-manifests-and-fingerprinting) to learn more about this capability.
* The built-in [authentication application](../../authentication/introduction.md) (which can be generated either through the use of the [`new`](../../development/reference/management-commands.md#new) management command or the [`auth`](../../development/reference/generators.md#auth) generator) now uses POST requests when signing out users.
* A [`play`](../../development/reference/management-commands.md#play) management command was introduced to make it easy to start a Crystal playground server initialized for the current project and open it in the default browser.
* The [`new`](../../development/reference/management-commands.md#new) management command can now generate project/app structures that use the development version of Marten when the `--edge` (or `-e`) option is used.
* A new [`trailing_slash`](../../development/reference/settings.md#trailing_slash) setting was introduced to configure whether an HTTP permanent redirect (301) should be issued when an incoming URL that does not match any of the configured routes either ends with a slash or does not.
* A new `--open` option was added to the [`serve`](../../development/reference/management-commands.md#serve) management command to make it possible to automatically open the development server in the default browser.
* New projects created through the use of the [`new`](../../development/reference/management-commands.md#new) management command now have the debug log level enabled in development (see [`log_level`](../../development/reference/settings.md#log_level)).

#### Security

* It is now possible to configure that the [CSRF](../../security/csrf.md) token must be persisted in the session store. This can be achieved by setting the [`use_session`](../../development/reference/settings.md#use_session) setting to `true`.

## Backward incompatible changes

### Handlers and HTTP

* Handlers making use of the [`Marten::Handlers::Schema`](pathname:///api/0.5/Marten/Handlers/Schema.html) generic handler (or schemas inheriting from it, such as [`Marten::Handlers::RecordCreate`](pathname:///api/0.5/Marten/Handlers/RecordCreate.html) or [`Marten::Handlers::RecordUpdate`](pathname:///api/0.5/Marten/Handlers/RecordUpdate.html)) will now return a **422 Unprocessable Content** response instead of a **200 OK** response when processing an invalid schema. While this won't have any incidence on end users, this change may make some specs fail if you were testing the response code of handlers that process invalid schema data. The way to fix this will be to replace `200` by `422` in the impacted specs.
