|
| 1 | +# Marten release: 0.6 |
| 2 | + |
| 3 | +We are pleased to announce the release of [Marten 0.6](https://martenframework.com/docs/the-marten-project/release-notes/0.6)! |
| 4 | + |
| 5 | +**Marten 0.6** brings significant enhancements, including localized routes, annotations, array schema fields, and image fields for models and schemas. These features make building apps with Marten smoother and more flexible. For a detailed overview of all new features and changes, check out the [full changelog](https://martenframework.com/docs/the-marten-project/release-notes/0.6). |
| 6 | + |
| 7 | +## New features and highlights |
| 8 | + |
| 9 | +### Localized routes |
| 10 | + |
| 11 | +Marten now provides the ability to define localized routes through the use of two mechanisms: automatically adding locale prefixes to routes and activating the appropriate locale based on the prefix, and translating the routes themselves. These mechanisms can be used independently or in combination. |
| 12 | + |
| 13 | +For example, the following routes map defines routes that will be prefixed by the currently activated locale and whose paths will be translated using the considered project's translations: |
| 14 | + |
| 15 | +```crystal |
| 16 | +ARTICLE_ROUTES = Marten::Routing::Map.draw do |
| 17 | + path t("routes.articles.list"), ArticlesHandler, name: "list" |
| 18 | + path t("routes.articles.create"), ArticleCreateHandler, name: "create" |
| 19 | + path t("routes.articles.detail"), ArticleDetailHandler, name: "detail" |
| 20 | + path t("routes.articles.update"), ArticleUpdateHandler, name: "update" |
| 21 | + path t("routes.articles.delete"), ArticleDeleteHandler, name: "delete" |
| 22 | +end |
| 23 | +
|
| 24 | +Marten.routes.draw do |
| 25 | + localized do |
| 26 | + path t("routes.landing"), LandingPageHandler, name: "landing" |
| 27 | + path t("routes.articles.prefix"), ARTICLE_ROUTES, name: "articles" |
| 28 | + end |
| 29 | +end |
| 30 | +``` |
| 31 | + |
| 32 | +As highlighted above, the use of routes prefixed with locales can be activated by wrapping route paths by a call to the [`#localized`](https://martenframework.com/docs/api/0.6/Marten/Routing/Map.html#localized(prefix_default_locale%3Dtrue%2C%26)%3ANil-instance-method) method. Route path translations can be defined using the [`#t`](https://martenframework.com/docs/api/0.6/Marten/Routing/Map.html#t(path%3AString)%3ATranslatedPath-instance-method) method, which assigns a translation key to each route (this key is then dynamically used to generate the route's path based on the active locale). |
| 33 | + |
| 34 | +With the routes map defined above, generated routes are fully localized and vary based on the currently activated locale: |
| 35 | + |
| 36 | +```crystal |
| 37 | +
|
| 38 | +I18n.activate("en") |
| 39 | +Marten.routes.reverse("landing") # => "/en/landing" |
| 40 | +Marten.routes.reverse("articles:create") # => "/en/articles/create" |
| 41 | +
|
| 42 | +I18n.activate("fr") |
| 43 | +Marten.routes.reverse("landing") # => "/fr/accueil" |
| 44 | +Marten.routes.reverse("articles:create") # => "/fr/articles/creer" |
| 45 | +``` |
| 46 | + |
| 47 | +Please refer to the [Localized routes](https://martenframework.com/docs/i18n/localized-routes) section of the documentation to learn more about this new capability. |
| 48 | + |
| 49 | +### Annotations |
| 50 | + |
| 51 | +Marten now lets you annotate query sets with aggregated data. This is useful when you need to "retain" aggregated values for each record in a query set (possibly for further filtering or for making use of the aggregated values when dealing with individual records). This can be achieved by using the [`#annotate`](https://martenframework.com/docs/models-and-databases/reference/query-set#annotate) method. |
| 52 | + |
| 53 | +For example: |
| 54 | + |
| 55 | +```crystal |
| 56 | +# Annotate the query set with the number of articles for each author. |
| 57 | +Author.all.annotate { count(:articles) } |
| 58 | +
|
| 59 | +# Get all the authors that have more than 10 articles. |
| 60 | +Author.all.annotate { count(:articles) }.where(articles_count__gt: 10) |
| 61 | +
|
| 62 | +# Order all the authors by the number of articles they have. |
| 63 | +Author.all.annotate { count(:articles) }.order(:articles_count) |
| 64 | +
|
| 65 | +# Access the annotated values for each author. |
| 66 | +authors = Author.all.annotate { count(:articles) } |
| 67 | +authors.each do |author| |
| 68 | + puts author.name |
| 69 | + puts author.annotations["articles_count"] |
| 70 | +end |
| 71 | +``` |
| 72 | + |
| 73 | +Please refer to the [Aggregations](https://martenframework.com/docs/models-and-databases/queries#aggregations) section of the documentation to learn more about this new capability. |
| 74 | + |
| 75 | +### Array schema field |
| 76 | + |
| 77 | +Marten now lets you define `array` schema fields that allow validating lists of values, with each value subject to the validation rules of an array member field (such as `string`, `int`, or any other existing [schema field type](https://martenframework.com/docs/schemas/reference/fields)). |
| 78 | + |
| 79 | +For example, the following schema allows validating lists of string values whose sizes must not be greater than 10: |
| 80 | + |
| 81 | +```crystal |
| 82 | +class TestSchema < Marten::Schema |
| 83 | + field :values, of: :string, max_size: 10 |
| 84 | +end |
| 85 | +``` |
| 86 | + |
| 87 | +As highlighted by the above example, the type of the underlying array member field must be specified through the use of an [`of`](https://martenframework.com/docs/schemas/reference/fields#of) option, which should reference an [existing schema field type](https://martenframework.com/docs/schemas/reference/fields#field-types) (such as `string`, `enum`, etc). |
| 88 | + |
| 89 | +Please refer to the [schema field reference](https://martenframework.com/docs/schemas/reference/fields#array) to learn more about `array` fields. |
| 90 | + |
| 91 | +### Image fields for models and schemas |
| 92 | + |
| 93 | +It is now possible to define `image` fields in [models](https://martenframework.com/docs/models-and-databases/reference/fields#image) and [schemas](https://martenframework.com/docs/schemas/reference/fields#image), which allow you to store or validate files that are indeed images. This capability requires the use of the [crystal-vips](https://github.com/naqvis/crystal-vips) shard. |
| 94 | + |
| 95 | +For example: |
| 96 | + |
| 97 | +```crystal |
| 98 | +class ImageAttachment < Marten::Model |
| 99 | + field :id, :big_int, primary_key: true, auto: true |
| 100 | + field :uploaded_file, :image, blank: false, null: false |
| 101 | +end |
| 102 | +
|
| 103 | +attachment = ImageAttachment.first! |
| 104 | +attachment.uploaded_file # => #<Marten::DB::Field::File::File:0x102dd0ac0 ...> |
| 105 | +attachment.uploaded_file.attached? # => true |
| 106 | +attachment.uploaded_file.name # => "test.png" |
| 107 | +attachment.uploaded_file.size # => 5796929 |
| 108 | +attachment.uploaded_file.url # => "/media/test.png" |
| 109 | +``` |
| 110 | + |
| 111 | +## Other changes |
| 112 | + |
| 113 | +Marten 0.6 also includes lots of additional changes and quality-of-life improvements. Head over to the [official Marten 0.6 release notes](https://martenframework.com/docs/the-marten-project/release-notes/0.6) for a full overview of everything in this release. |
0 commit comments