>
+```
+
+Over in the unit tests, however, if you want to test `CreateThing` in isolation from the `service_client`, you can pass in an explicit replacement for this default dependency.
+
+```ruby
+subject(:create_thing) {
+ CreateThing.new(service_client: service_client)
+}
+
+let(:service_client) { spy(:service_client) }
+```
+
+This low friction approach to dependency injection means you can much more readily decompose our application behaviour into smaller, easier-to-understand, easier-to-test, single-responsibility components.
+
+## Application settings
+
+Application settings loading is now built-in. You can define these in `config/settings.rb`:
+
+```ruby
+Hanami.application.settings do
+ setting :some_service_api_key
+end
+```
+
+An optional type object can be provided as a second argument, to coerce and/or type check the setting values. This works well with [dry-types](https://dry-rb.org/gems/dry-types) type objects.
+
+Settings are read from `.env*` files using [dotenv](https://github.com/bkeepers/dotenv).
+
+The resulting settings object is a struct with methods matching your setting names. Itβs available as `Hanami.application.settings` as well as via the `"settings"` component, allowing you to auto-inject it into your application components as required.
+
+## Application and slices
+
+So far our examples have been from a single all-in-one application. But as our apps grow in complexity, it can be helpful to separate them into distinct, well-bounded high-level concerns. To serve in this role, Hanami 2 offers **Slices**.
+
+Slices live inside the `slices/` directory. Each slice maps onto a single Ruby module namespace, and has its own dedicated instance for managing its components.
+
+For an application with the following directories:
+
+```ruby
+slices/
+ admin/
+ main/
+ search/
+```
+
+It would have corresponding `Admin`, `Main`, and `Search` slices. Each slice is loaded and managed just like the application itself, so a class defined in `admin/create_article.rb` would be available from `Admin::Slice` as `Admin::Slice["create_article"]`, and can in turn inject other dependencies from the admin slice.
+
+```ruby
+module Admin
+ class CreateArticle
+ include Deps["contracts.article_contract"] # defaults to Admin::Contracts::ArticleContract
+ end
+end
+```
+
+Each slice also automatically imports the components from the application, which contains some common facilities (like the logger), the appβs top-level bootable components, as well as any other classes you define in `lib/`. These are available under an `"application."` namespace in the slice, making it just as easy to inject these as dependencies.
+
+```ruby
+module Admin
+ class CreateArticle
+ include Deps[
+ "contracts.article_contract",
+ "application.logger",
+ ]
+
+ def call
+ logger.info "creating article"
+ # ...
+ end
+ end
+end
+```
+
+Slices can also _import each other._
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ config.slice :admin do
+ # Inside `Admin`, registrations from the `Search` slice will be available under the `"search."` container namespace
+ import :search
+ end
+ end
+end
+```
+
+With this, the slices themselves form their own clear graph of your applicationβs high-level functionality.
+
+While the slices are already incredibly powerful thanks to the built-in features of the container, weβll be spending future release cycles bolstering these even further, such as making it possible to load slices conditionally.
+
+## Functional Hanami::Action
+
+`Hanami::Action` has been reoriented to provide immutable, callable action classes that fit well with all other parts of the new framework. Actions can declare dependencies to interact with the rest of the application, access the request and prepare a response in their `#handle` method, then the class will take care of the rest.
+
+```ruby
+module Admin
+ module Actions
+ module Articles
+ class Show < Admin::Action
+ include Deps["article_repo"]
+
+ def handle(req, res)
+ article = article_repo.find(req.params[:id])
+
+ res.body = JSON.generate(article)
+ end
+ end
+ end
+ end
+end
+```
+
+Actions are still callable and Rack-compatible, and continue to offer the same range of HTTP-related features from their 1.x counterparts, reoriented to fit this new structure.
+
+## Brand new view layer
+
+Hanami 2.0 will sport an entirely new view layer, with [dry-view](https://dry-rb.org/gems/dry-view) joining the Hanami family as the new hanami-view. With years of development behind it, it offers a sophisticated set of abstractions for designing well-factored views.
+
+A view in Hanami 2.0 is a standalone, callable class that can declare dependencies to interact with the rest of the application (are you catching the theme here?). It can access parameters and then prepare named exposures to make available to its corresponding template.
+
+```ruby
+module Admin
+ module Views
+ module Articles
+ class Show < Admin::View
+ include Deps["article_repo"]
+
+ expose :article do |id:|
+ article_repo.find(id)
+ end
+ end
+ end
+ end
+end
+```
+
+Every exposureβs value is decorated by a matching view part class, which you can use to provide view-specific behaviour attached to specific domain objects, including anything possible from within the templates, such as rendering partials and accessing all aspects of the general view rendering context.
+
+```ruby
+module Admin
+ module View
+ module Parts
+ class Article < Admin::Part
+ def preview_text
+ body_text.to_s[0..300]
+ end
+
+ def render_social_preview
+ render(:social_preview, title: title, text: preview_text)
+ end
+ end
+ end
+ end
+end
+```
+
+Views also integrate nicely with actions, allowing you to keep your actions clean and focused on HTTP responsibilities only.
+
+```ruby
+module Admin
+ module Actions
+ module Articles
+ class Show < Admin::Action
+ include Deps[view: "views.articles.show"]
+
+ def handle(req, res)
+ res.render view, id: req.params[:id]
+ end
+ end
+ end
+ end
+end
+```
+
+Since views are independent, addressable, callable objects just like any other component within an Hanami application, they can also be put to a wide range of uses alongside the standard rendering of web page HTML, such as rendering emails or even preparing API responses.
+
+## Zero-boilerplate integration of application components
+
+A strong focus of our effort in building Hanami 2.0 has been to allow each component, such as a view or action, to remain useful outside of Hanami, while also fitting seamlessly when used within a full Hanami application. A view used outside of Hanami, for example, looks like this:
+
+```ruby
+class MyView < Hanami::View
+ config.template = "my_view"
+end
+```
+
+And this same view used within Hanami looks like this:
+
+```ruby
+class MyView < Hanami::View
+end
+```
+
+Thereβs almost no difference! Once you understand how to use `Hanami::View` in one place, you can use it everywhere. Even inside an Hanami app, where the app seamlessly integrates the views (in the case above, inferring the template name automatically, among other things), you can still access the full extent of the view configuration, allowing you to βejectβ from the configured defaults if you ever need.
+
+## Blazing fast new router
+
+With all your actions and views in place, youβll want a way to write them up to URLs. Hanami 2.0βs router will offer a familiar DSL to make this happen.
+
+```ruby
+Hanami.application.routes do
+ mount :main, at: "/" do
+ # Will resolve "actions.home.index" from the Main slice
+ root to: "home#index"
+ end
+
+ mount :admin, at: "/admin" do
+ # Will resolve "actions.home.index" from the Admin slice
+ root to: "home#index"
+ end
+end
+```
+
+The engine underpinning the new router also offers amazing performance, with Hanami::API benchmarks showing it [outperforming nearly all others](https://hanamirb.org/blog/2020/02/26/introducing-hanami-api/).
+
+## A framework for all applications
+
+Many of the new features weβve seen so far would empower any kind of application, not just web applications. So with this alpha, weβre making the first release of a truly βunbundledβ Hanami, with the hanami-controller, hanami-router, and hanami-view gem dependencies being moved outside of the main gem and into the Gemfiles of the generated applications.
+
+This means you can now use the hanami gem to help you better organise any kind of Ruby application. All youβll need to do is opt out of the web mode when booting your application.
+
+```
+Hanami.boot web: false
+```
+
+In future releases, weβll work to make this an even smoother process.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.alpha2
+- `hanami-cli` v2.0.0.alpha2
+- `hanami-view` v2.0.0.alpha2
+- `hanami-controller` v2.0.0.alpha2
+- `hanami-router` v2.0.0.alpha5
+- `hanami-utils` v2.0.0.alpha2
+
+## How can I try it?
+
+Weβve prepared an [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template) which you can clone to get started with an app and try everything weβve shared today. The template provides itβs own installation instructions and scripts, and prepares a full stack web application ready for you to use.
+
+Thereβs so much more to this release than weβve been able to share in this brief post, so weβd love for you to try everything out. We canβt wait to hear your thoughts!
+
+## Whatβs next?
+
+While weβve covered so much ground since the last alpha, there are still many rough edges to smooth over, as well as a few big pieces to put in place, such as an application CLI with generators, first-class integration with [rom-rb](https://rom-rb.org) for a persistence layer, front-end assets integration, and a standard collection of view helpers.
+
+If youβd like to follow along, weβre tracking the remaining work in our public [Hanami 2.0 trello board](https://trello.com/b/lFifnBti/hanami-20).
+
+Thank you for your continued interest in Hanami, and for your support of a diverse, flourishing Ruby ecosystem! πΈ
diff --git a/source/blog/2021-05-04-announcing-hanami-200alpha2/cover.jpg b/source/blog/2021-05-04-announcing-hanami-200alpha2/cover.jpg
new file mode 100644
index 000000000..5e46f4f63
Binary files /dev/null and b/source/blog/2021-05-04-announcing-hanami-200alpha2/cover.jpg differ
diff --git a/source/blog/2021-06-18-new-git-branches.html.markdown b/source/blog/2021-06-18-new-git-branches.html.markdown
new file mode 100644
index 000000000..41e5ecd90
--- /dev/null
+++ b/source/blog/2021-06-18-new-git-branches.html.markdown
@@ -0,0 +1,28 @@
+---
+title: New Git Branches
+date: 2021-06-18 06:57:41 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ New Git branches system, renamed master in favor of main. Main contains code for Hanami 2.0.
+---
+
+Hello, Hanami community!
+We put in place a simplified Git branches system.
+
+**TL;DR: Renamed `master` into `main`. `main` contains the code for Hanami 2.0.**
+
+Let's have a look at the details. For all the Hanami GitHub repositories:
+
+ * `master` , `develop`, `unstable` branches are gone
+ * `master` branches were merged into _stable branches_ (see below)
+ * Example: `hanami/hanami` `master` branch was hosting Hanami 1.3 code. Now that code is part of the `1.3.x` branch.
+ * `main` is the new default branch for all the repositories
+ * `main` hosts the new work, new features (aka Hanami 2)
+ * **Use these branches to merge new features**
+ * _Stable branches_ host the maintenance work (aka Hanami 1).
+ * They are named after SemVer `Major.Minor.x` (e.g. `1.3.x`).
+ * **Use these branches for maintenance**
+
+βΉοΈ CI status for `main` and _stable branches_ can be observed in the π¦ [status](/status) page of our website.
diff --git a/source/blog/2021-06-18-new-git-branches/cover.jpg b/source/blog/2021-06-18-new-git-branches/cover.jpg
new file mode 100644
index 000000000..0dd4ffddb
Binary files /dev/null and b/source/blog/2021-06-18-new-git-branches/cover.jpg differ
diff --git a/source/blog/2021-10-18-announcing-hanami-135.html.markdown b/source/blog/2021-10-18-announcing-hanami-135.html.markdown
new file mode 100644
index 000000000..9dfaf8775
--- /dev/null
+++ b/source/blog/2021-10-18-announcing-hanami-135.html.markdown
@@ -0,0 +1,57 @@
+---
+title: Announcing Hanami v1.3.5
+date: 2021-10-18 10:03:14 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Patch release for bugfixes. New default serializer (JSON) for HTTP session Cookies storage.
+---
+
+Hello wonderful community!
+
+Today we're happy to announce `v1.3.5` π.
+
+## Changed β©
+
+ * Use JSON as default HTTP session serializer for cookie session storage
+
+## Bug Fixes π
+
+ * Ensure to properly store exceptions in Rack environment
+ * Explicitly limit in gemspec the supported rubies (>= 2.3 and < 3) for Hanami 1k
+ * Ensure `.validations` to not raise `NoMethodError: undefined method 'size' for nil:NilClass`. Due to a breaking change in transitive dependency (`dry-configurable` `0.13.x`).
+
+## Released Gems π
+
+ * `hanami` `v1.3.5`
+ * `hanami-validations` `v1.3.8`
+
+## How to install β¨οΈ
+
+```shell
+$ gem install hanami
+$ hanami new bookshelf
+```
+
+## How to upgrade β¬
+
+```shell
+$ bundle update hanami
+```
+
+β οΈ **If you're using HTTP sessions with cookies (default), please note that we changed the default session serializer from `Rack::Session::Cookie::Base64::Marshal` (Rack default) to `Rack::Session::Cookie::Base64::JSON`.**β οΈ
+
+We received a security disclosure that proves that `Marshal` based serialization is vulnerable to an attack.
+To know more, please read the discussion over [GitHub](https://github.com/hanami/hanami/pull/1127).
+
+To **upgrade** your application:
+
+1. Update `hanami` version (`bundle update hanami`)
+2. Rotate the session secret in production (usually `WEB_SESSIONS_SECRET` in `.env`). This will cause an expiration of current HTTP sessions. This is needed because you're going to change the low level (de)serialization mechanism of HTTP sessions.
+3. Deploy the app
+
+Special thanks go to ooooooo_q and [Maciej Mensfeld](https://github.com/mensfeld) for the security disclosure and their help handling this case.
+We're very thankful. π
+
+Happy coding! πΈ
diff --git a/source/blog/2021-10-18-announcing-hanami-135/cover.jpg b/source/blog/2021-10-18-announcing-hanami-135/cover.jpg
new file mode 100644
index 000000000..23765b3ac
Binary files /dev/null and b/source/blog/2021-10-18-announcing-hanami-135/cover.jpg differ
diff --git a/source/blog/2021-11-09-announcing-hanami-200alpha3.html.markdown b/source/blog/2021-11-09-announcing-hanami-200alpha3.html.markdown
new file mode 100644
index 000000000..f29426ed0
--- /dev/null
+++ b/source/blog/2021-11-09-announcing-hanami-200alpha3.html.markdown
@@ -0,0 +1,165 @@
+---
+title: Announcing Hanami v2.0.0.alpha3
+date: 2021-11-09 13:30:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Streamlined source directories, more flexible settings, better integrated actions, and the beginning of a monthly release cadence.
+---
+
+Hello Hanami community! Itβs Tim here again, and Iβm delighted to announce the release of Hanami 2.0.0.alpha3!
+
+This release represents months of work on several foundational aspects of the framework, and brings:
+
+- Shallow application source directories
+- Reworked application settings
+- Reworked application routes
+- Actions enhancements
+- Framework settings are now powered by dry-configurable
+
+## Streamlined application directories
+
+**tl;dr** we simplified the source directory structures, `slices/main/lib/main/my_class.rb` will now be `slices/main/lib/my_class.rb`
+
+In our previous alpha release, we required you to structure your source files in a way that matched the typical Ruby conventions for loading from the `$LOAD_PATH`. So if you had a `main` slice, and a `Main::MyClass` component, it would need to be located at `slices/main/lib/main/my_class.rb`. This worked well enough, but it presented awkwardly deep directory trees with redundant names, especially given we expect all components defined within each slice to live within its own singular namespace anyway. This latter aspect was already made clear by the fact that we removed that redundant leading "main" from the componentβs key, with it available from the slice as `Main::Slice["my_class"]`.
+
+So for this release, we made a major overhaul to our code loading to support our ideal source directory structure. Now in your `main` slice, your `Main::MyClass` component can be defined directly within itβs `lib/` directory, at `slices/main/lib/my_class.rb`, while still available from the slice as `Main::Slice["my_class"]`. This means one fewer directory to hop through, one less name to say when youβre communicating your source paths, and a much stronger signal that each slice should fully inhabit its own namespace.
+
+Along with this, you can now keep certain categories of components in their own top-level directories, including `actions/`, `repositories/`, and `views/`. With this, you can define an action like `Main::Actions::Posts::Index` in `slices/main/actions/posts/index.rb`, with the component accessible from the slice as `Main::Slice["actions.posts.index"]`.
+
+Together, these changes should make surveying and navigating both your sliceβs business logic and its top-level entry points much easier.
+
+## Application no longer auto-registers components from `lib/`
+
+As of this release, classes inside `lib/` (unlike `slices/`) no longer auto-register as application components.
+
+If you wish to register a component with the application, you should create a file in `config/boot/` like [this example](https://github.com/hanami/hanami-2-application-template/blob/3ba7724a75272b61d52d628bdbbb6f90416645dc/config/boot/assets.rb) in our current application template.
+
+The idea with this change is to help minimize the coupling across the application overall. Components within the application are automatically imported into all slices (e.g. with the `Hanami.application["logger"]` also available as `Main::Slice["application.logger"]`), so the fewer application-wide components you carry, the better. In addition, Hanami gives you another option for more intentional sharing of behavior: more slices! If thereβs a distinct subset of related components that you want to make accessible to numerous other slices, you should define them within their own slice, and import that wherever needed. You can currently achieve this like so (and weβll be working to make it more ergonomic in future releases):
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ config.slice :main do
+ # Importing a common "search" slice into the main slice; all components from the search
+ # slice will be accessible with keys prefixed by "search."
+ import :search
+ end
+ end
+end
+```
+
+While weβre encouraging you to look to additional slices for sharing components, we still want to make it straightforward to share and access other aspects of common behavior across your application. To this end, weβve clarified the autoloading rules for `lib/`: now, every file under the applicationβs namespace (such as `lib/my_app/my_class.rb`) will be autoloaded and available without explicit requires, to ensure the experience is consistent across both the application and slice namespaces.
+
+All files in `lib/` outside the application namespace (such as `lib/some/other/class.rb`) will _not_ be autoloaded, and will need a `require` just like working with regular Ruby gems. This gives you a place to build out non-core, complementary code in your application without it being interfered with by the autoloader.
+
+## Reworked application settings
+
+As of this release, your application settings are now no longer defined within an anonymous block, and are instead delivered as a concrete class, still defined in `config/settings.rb`:
+
+```ruby
+require "hanami/application/settings"
+
+module MyApp
+ class Settings < Hanami::Application::Settings
+ setting :my_secret
+ end
+end
+```
+
+The benefit these living within a class is that it gives us a place to hang all sorts of regular Ruby code to enhance the settings loading and delivery. For instance, itβs now possible to define an inline types module with [dry-types](https://dry-rb.org/gems/dry-types), to provide an expressive types library for validating and coercing your settings:
+
+```ruby
+require "dry/types"
+require "hanami/application/settings"
+
+module MyApp
+ class Settings < Hanami::Application::Settings
+ Types = Dry.Types()
+
+ setting :my_secret, constructor: Types::String.constrained(min_size: 20)
+ end
+end
+```
+
+And since the settings are based on [dry-configurable](https://dry-rb.org/gems/dry-configurable), you can now easily provide default values, too:
+
+```ruby
+setting :my_bool, constructor: Types::Params::Bool, default: false
+```
+
+And finally, with a class at your disposal, you can also add your own methods to provide the best and most fit for purpose interface to your application settings:
+
+```ruby
+require "dry/types"
+require "hanami/application/settings"
+
+module MyApp
+ class Settings < Hanami::Application::Settings
+ Types = Dry.Types()
+
+ setting :some_account_key, constructor: Types::String.optional
+
+ def some_account_enabled?
+ !!some_account_key
+ end
+ end
+end
+```
+
+## Reworked application routes
+
+Weβve also reworked the application routes to match the approach weβve taken for the settings. As of this release, your `config/routes.rb` will no look something like this:
+
+```ruby
+require "hanami/application/routes"
+
+module MyApp
+ class Routes < Hanami::Application::Routes
+ define do
+ slice :main, at: "/" do
+ root to: "home.show"
+ end
+ end
+ end
+end
+```
+
+For now, switching from the anonymous block to the concrete class is the extent of the change, but we expect this will provide a useful hook for your own custom behavior in the future, too. Watch this space.
+
+## Actions enhancements
+
+We have a assortment of small quality of life improvements to actions for this release:
+
+- Session behavior within actions is now automatically included whenever sessions are enabled via your application-level settings.
+- Automatic view rendering how now been moved out of the default implementation of `Hanami::Action#handle` method, which is the where we expect you to put your own custom logic. With this change, youβll no longer need to call `super` if you want to keep the automatic view rendering behavior.
+- All action exposures are now automatically passed to the view for rendering (and will be passed onto your template if you provide a same-named exposure in your view class)
+
+## Framework settings ported to dry-configurable
+
+This is a mostly internal change, but the framework settings defined in `Hanami::Configuration` and exposed as `Hanami.application.config` are now largely provided by [dry-configurable](https://dry-rb.org/gems/dry-configurable), which will has made them significantly easier to maintain, and will provide us with some better building blocks for more extensible settings in future.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.alpha3
+- `hanami-cli` v2.0.0.alpha3
+- `hanami-view` v2.0.0.alpha3
+- `hanami-controller` v2.0.0.alpha3
+- `hanami-utils` v2.0.0.alpha3
+
+## How can I try it?
+
+You can check out our [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template), which is up to date for this latest release and ready for you to use out as the starting point for your own app.
+
+Weβd really love for you to give the tires a good kick for this release in this particular: the more real-world testing we can have of our code loading changes, the better!
+
+## Whatβs coming next?
+
+As of this alpha release, we believe weβve now jumped the biggest hurdles in preparing the overall Hanami 2 structure.
+
+From this point forward, **weβll be making monthly alpha releases**, bringing together all the work from the month and making it easily accessible to you, along with high-level release announcements like this one. Weβre excited to pick up the pace of development from here, and to round out the Hanami 2 vision with you along for the ride!
+
+Thank you as ever for your support of Hanami! We canβt wait to hear from you about this release, and weβre looking forward to checking in with you again next month. ππ»ββοΈπΈ
diff --git a/source/blog/2021-11-09-announcing-hanami-200alpha3/cover.jpg b/source/blog/2021-11-09-announcing-hanami-200alpha3/cover.jpg
new file mode 100644
index 000000000..5e46f4f63
Binary files /dev/null and b/source/blog/2021-11-09-announcing-hanami-200alpha3/cover.jpg differ
diff --git a/source/blog/2021-12-07-announcing-hanami-200alpha4.html.markdown b/source/blog/2021-12-07-announcing-hanami-200alpha4.html.markdown
new file mode 100644
index 000000000..fbc282989
--- /dev/null
+++ b/source/blog/2021-12-07-announcing-hanami-200alpha4.html.markdown
@@ -0,0 +1,120 @@
+---
+title: Announcing Hanami v2.0.0.alpha4
+date: 2021-12-07 13:15:19 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ New API for Content Security Policy, Router helpers from actions, CLI enhancements.
+---
+
+Hello Hanami community! We're thrilled to announce the release of Hanami 2.0.0.alpha4!
+
+With this new cycle of monthly based releases we have smaller set of changes, but delivered more frequently.
+
+Specifically, we're focusing on the cleanup of our application template.
+The template is essential for **you** to try Hanami 2, but also for **us** to shape the ergonomics of the framework.
+
+ * Content Security Policy (new API)
+ * Router helpers to be accessible from actions
+ * CLI enhancements
+
+## Content Security Policy
+
+We proudly share this story: Hanami was **the first Ruby framework** to ship with [Content Security Policy (CSP)](https://en.wikipedia.org/wiki/Content_Security_Policy) support.
+
+In Hanami 1 the public API to handle CSP was less than optimal.
+You had to deal with a string blob, with all the complexity of CSP keys and their values.
+That was error prone and β frankly β ugly to see.
+
+Let's start from the last concern: **you won't see CSP setting in newly generated Hanami 2 applications**.
+Hanami 2 now has a default CSP shipped with the framework, instead of generating it during application creation.
+First problem solved. π
+
+If you need to change a value, or turn off the feature, the [API is simplified](https://github.com/hanami/controller/pull/353).
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ # This line will generate the following CSP fragment
+ # script-src 'self' https://my.cdn.test;
+
+ config.actions.content_security_policy[:script_src] += " https://my.cdn.test"
+ end
+end
+```
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ config.actions.content_security_policy = false
+ end
+end
+```
+
+Second problem solved. βοΈ
+
+## Router Helpers
+
+Router helpers are now accessible from actions as `routes`.
+It exposes two methods: `url` for absolute URLs and `path` for relative ones.
+
+It accepts a `Symbol` that corresponds to the named route (e.g. `:book`) and a set of arbitrary arguments to interpolate the route variables (e.g. `:id`).
+
+```ruby
+# frozen_string_literal: true
+
+require "hanami/application/routes"
+
+module AppPrototype
+ class Routes < Hanami::Application::Routes
+ define do
+ slice :admin, at: "/admin" do
+ get "/book/:id" to: "book.show", as: :book
+ end
+ end
+ end
+end
+```
+
+```ruby
+module Admin
+ module Actions
+ module Books
+ class Update < Admin::Action
+ def handle(*, res)
+ # update the book
+
+ res.redirect_to routes.url(:book, id: book.id)
+ end
+ end
+ end
+ end
+end
+```
+
+## CLI enhancements
+
+Minor enhancements for the command line:
+
+ * Display a custom prompt when using IRB based console (consistent with PRY based console)
+ * Support `postgresql://` URL schemes (in addition to existing `postgres://` support) for `db` subcommands
+ * Ensure slice helper methods work in console (e.g. top-level `main` method will return `Main::Slice` if an app has a "main" slice defined)
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.alpha4
+- `hanami-controller` v2.0.0.alpha4
+- `hanami-cli` v2.0.0.alpha4
+
+## How can I try it?
+
+You can check out our [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template), which is up to date for this latest release and ready for you to use out as the starting point for your own app.
+
+Weβd really love for you to give the tires a good kick for this release in this particular: the more real-world testing we can have of our code loading changes, the better!
+
+## Whatβs coming next?
+
+Thank you as ever for your support of Hanami! We canβt wait to hear from you about this release, and weβre looking forward to checking in with you again next month. ππ»ββοΈπΈ
diff --git a/source/blog/2021-12-07-announcing-hanami-200alpha4/cover.jpg b/source/blog/2021-12-07-announcing-hanami-200alpha4/cover.jpg
new file mode 100644
index 000000000..5e46f4f63
Binary files /dev/null and b/source/blog/2021-12-07-announcing-hanami-200alpha4/cover.jpg differ
diff --git a/source/blog/2022-01-12-announcing-hanami-200alpha5.html.markdown b/source/blog/2022-01-12-announcing-hanami-200alpha5.html.markdown
new file mode 100644
index 000000000..95d875b3f
--- /dev/null
+++ b/source/blog/2022-01-12-announcing-hanami-200alpha5.html.markdown
@@ -0,0 +1,219 @@
+---
+title: Announcing Hanami v2.0.0.alpha5
+date: 2022-01-12 11:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Sensible default logger, full source dirs config, router loading flexibility, route helpers in views
+---
+
+Happy new year, Hanami community! To get 2022 started, we're excited to announce the release of Hanami 2.0.0.alpha5!
+
+This release brings the last month of our work on Hanami 2.0 (with an extra week added for good measure, while we all returned from our end of year breaks). It includes:
+
+- Sensible default configuration for the application logger
+- Comprehensive source dirs configuration (for advanced users)
+- Lazy router and Rack app initialization
+- Access to the application route helpers from the view context
+- RSS support in our default MIME type list
+
+## Default application logger configuration
+
+In our ongoing effort to strip boilerplate from our [application template](https://github.com/hanami/hanami-2-application-template), we now ship a sensible default configuration for the application logger.
+
+The defaults are:
+
+- In **production**, log for level `info`, send logs to `$stdout` in JSON format without colors
+- In **development**, log for level `debug`, send logs to `$stdout` in single-line format with colors
+- In **test**, log for level `debug`, send logs to `log/test.log` in single-line format without colors
+
+These defaults mean we've now achieved sensible behavior for a zero-configuration Hanami application class:
+
+```ruby
+# config/application.rb
+
+require "hanami"
+
+module MyApp
+ class Application < Hanami::Application
+ end
+end
+```
+
+You can customize the logger config as much as you need:
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ config.logger.level = :info
+
+ config.logger.stream = $stdout
+ config.logger.stream = "/path/to/file"
+ config.logger.stream = StringIO.new
+
+ config.logger.format = :json
+ config.logger.format = MyCustomFormatter.new
+
+ config.logger.color = false # disable coloring
+ config.logger.color = MyCustomColorizer.new
+
+ config.logger.filters << "secret" # add
+ config.logger.filters += ["yet", "another"] # add
+ config.logger.filters = ["foo"] # replace
+
+ # See https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html
+ config.logger.options = ["daily"] # time based log rotation
+ config.logger.options = [0, 1048576] # size based log rotation
+ end
+end
+```
+
+You can also customize the config specifically for given environments:
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ config.environment(:staging) do
+ config.logger.level = :info
+ end
+ end
+end
+```
+
+And finally, you can assign a completely custom logger object:
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ config.logger = MyCustomLogger.new
+ end
+end
+```
+
+## Comprehensive source dirs configuration (for advanced users)
+
+In the 2.0.0.alpha3 release, we introduced [streamlined source directories](/blog/2021/11/09/announcing-hanami-200alpha3/) for the Ruby source files within each slice. Just like weβre doing with our application logger, we ship a sensible default configuration out of the box. Now with alpha5, weβre introducing a new `config.source_dirs` setting that you can use to fully customize this configuration.
+
+This will allow you to add and configure your own additional component dirs (which are the directories used to auto-register application components):
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ # Adding a simple component dir
+ config.source_dirs.component_dirs.add "serializers"
+
+ # Adding a component dir with custom configuration
+ config.source_dirs.component_dirs.add "serializers" do |dir|
+ dir.auto_register = proc { |component|
+ !component.identifier.start_with?("structs")
+ }
+ end
+ end
+end
+```
+
+You can also customize the configuration of the default component dirs ("lib", "actions", "repositories", "views"):
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ # Customising a default component dir
+ config.source_dirs.component_dirs.dir("lib").auto_register = proc { |component|
+ !component.identifier.start_with?("structs")
+ }
+
+ # Setting default config to apply to all component dirs
+ config.source_dirs.component_dirs.auto_register = proc { |component|
+ !component.identifier.start_with?("entities")
+ }
+
+ # Removing a default component dir
+ config.source_dirs.component_dirs.delete("views")
+ end
+end
+```
+
+The `config.source_dirs.component_dirs` setting is provided by [dry-systemβs](http://dry-rb.org/gems/dry-system/0.21/) own `Dry::System::Config::ComponentDirs`, so you can use this to configure any aspect of component loading as you require.
+
+In addition to component dirs, you can also configure your own autoload paths, for source files you donβt want registered as components, but whose classes you still want to access inside your application. These directories are helpful for any classes that you will directly instantiate with their own data rather than dependencies, such as entities, structs, or any other kind of value class.
+
+Out of the box, our `autoload_paths` is `["entities"]`. You can configure this as required:
+
+```ruby
+module MyApp
+ class Application < Hanami::Application
+ # Adding your own autoload paths
+ config.source_dirs.autoload_paths << "structs"
+
+ # Or providing a full replacement
+ config.source_dirs.autoload_paths = ["structs"]
+ end
+end
+```
+
+## Lazy router and Rack app initialization
+
+One of the most powerful features of Hanami 2 is your ability to partially boot the application, loading only the specific components you need to complete a particular task. This makes testing considerably faster, but it also opens up flexible deployment opportunities, such as optimising the performance of certain production workloads by only loading particular subsets of your application.
+
+With this release, this flexibility has been extended to the application router and its Rack interface, which are now initialized lazily, allowing you to access the router and rack app even if your application has not fully booted. The rack app is now available as `.rack_app` on your application class, and can be accessed at any time after the applicationβs initial "init" step:
+
+```ruby
+# Example config.ru
+
+# Loads the Hanami app at config/application.rb and runs Hanami.init
+#
+# n.b. this does _not_ fully boot the application, so most components are not
+# loaded, but routes are still accessible and their supporting components will
+# also be lazily loaded when required
+require "hanami/init"
+
+run Hanami.rack_app
+```
+
+Access to the Rack app in this way opens up the possibility of a slimline deployment of a your application configured to serve only a small subset of its overall routes. In this case, only the minimal subset of components will be loaded to serve the given routes. This may be helpful for fine-grained deployment to resource-constrained targets like serverless functions.
+
+Closer to home, this is also the first step towards faster code reloading when running the application in development mode. Weβll be working on this in future releases.
+
+## Route helpers via the view context
+
+Last month we made the [route helpers available in actions](/blog/2021/12/07/announcing-hanami-200alpha4/), and now weβre making them available in views too, via our default [view context](https://dry-rb.org/gems/dry-view/0.7/context/). This means you can access `routes` inside any template:
+
+```slim
+/ slices/main/web/templates/books/index.html.slim
+
+- books.each do |book|
+ p
+ a href=routes.url(:book, id: book.id) = book.title
+```
+
+Given the context is exposed to view [parts](https://dry-rb.org/gems/dry-view/0.7/parts/) and [scopes](https://dry-rb.org/gems/dry-view/0.7/scopes/), you can access `routes` there as well.
+
+## RSS support in our default MIME type list
+
+You can now configure your Hanami actions to work with RSS formatted requests and responses via the new `rss` entry in our default MIME types list.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami v2.0.0.alpha5`
+- `hanami-controller v2.0.0.alpha5`
+- `hanami-view v2.0.0.alpha5`
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Philip Arndt](https://github.com/parndt/)
+- [Tim Riley](https://github.com/timriley)
+
+## How can I try it?
+
+You can check out our [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template), which is up to date for this release and ready for you to try as the starting point for your own app.
+
+## Whatβs coming next?
+
+Weβll be back in February for alpha6, bringing our next month of development direct to you.
diff --git a/source/blog/2022-01-12-announcing-hanami-200alpha5/cover.jpg b/source/blog/2022-01-12-announcing-hanami-200alpha5/cover.jpg
new file mode 100644
index 000000000..5e46f4f63
Binary files /dev/null and b/source/blog/2022-01-12-announcing-hanami-200alpha5/cover.jpg differ
diff --git a/source/blog/2022-02-10-announcing-hanami-200alpha6.html.markdown b/source/blog/2022-02-10-announcing-hanami-200alpha6.html.markdown
new file mode 100644
index 000000000..9c1e39f55
--- /dev/null
+++ b/source/blog/2022-02-10-announcing-hanami-200alpha6.html.markdown
@@ -0,0 +1,165 @@
+---
+title: Announcing Hanami v2.0.0.alpha6
+date: 2022-02-10 11:04:32 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Hanami Providers, Partial Slice Import/Export. Ruby 3.0+ only.
+---
+
+Hello Hanami community! We're thrilled to announce the release of Hanami 2.0.0.alpha6!
+
+With this new cycle of monthly based releases we have a smaller set of changes, but delivered more frequently.
+
+This month we focused mainly on the internals of the framework.
+The work that Tim Riley is doing is epic.
+Hanami 2 is modeled around dry-system, which powers the booting process and the dependencies of an app.
+
+## Hanami Providers
+
+First thing first, **we renamed _bootable compontents_ into _providers_**.
+This change was reflected in the public API.
+
+We also renamed the provider `init` lifecycle step to `prepare`.
+
+```ruby
+Hanami.application.register_provider(:metrics) do
+ prepare do
+ require "datadog/statsd"
+ end
+
+ start do
+ # See application's config/settings.rb
+ settings = target[:settings].statsd
+
+ register "metrics", Datadog::Statsd.new(settings.host, settings.port)
+ end
+
+ stop do
+ # triggered when the application is shut down
+ metrics.close
+ end
+end
+```
+
+```ruby
+module API
+ module Actions
+ module Users
+ class Create < API::Action
+ include Deps["application.metrics"]
+
+ def handle(req, res)
+ # ...
+ metrics.increment("user.create")
+ end
+ end
+ end
+ end
+end
+```
+
+Read more about Provider's changes in [CHANGELOG](https://github.com/hanami/hanami/blob/main/CHANGELOG.md#v200alpha6---2022-02-10).
+
+## Partial Slice Import/Export
+
+A Slice in your application can be used to provide a single responsibility functionality.
+You can think of it as having **microservices in your monolith** but without the complexity!
+
+For instance, the `search` Slice can expose the search functionality to other slices.
+
+To ensure unwanted functionalities exports, you have the option of declaring which functionalities to export.
+Here's a few examples
+
+Import from `search` slice, uses `search` as the imported key namespace:
+
+```ruby
+# config/application.rb
+
+module MyApp
+ class Application < Hanami::Application
+ config.slice(:admin) do
+ import(from: :search)
+ end
+ end
+end
+```
+
+Import from `search` slice with custom namespace:
+
+```ruby
+# config/application.rb
+
+module MyApp
+ class Application < Hanami::Application
+ config.slice(:admin) do
+ import(from: :search, as: :search_engine)
+ end
+ end
+end
+```
+
+Import specific keys from `search` slice
+
+```ruby
+# config/application.rb
+
+module MyApp
+ class Application < Hanami::Application
+ config.slice(:admin) do
+ import(keys: ["run_query"], from: :search)
+ end
+ end
+end
+```
+
+Export only specific keys from `search` slice, and import them in `admin`
+
+```ruby
+# config/application.rb
+
+module MyApp
+ class Application < Hanami::Application
+ config.slice(:admin) do
+ import(from: :search)
+ end
+
+ config.slice(:search) do
+ container.config.exports = %w[run_query index_item]
+ end
+ end
+end
+```
+
+## Ruby 3.0+ only
+
+We took this decision for a clear cut with the past of Ruby.
+At the time of the writing (Feb 2022), Ruby 2.6 will reach [End Of Life](https://www.ruby-lang.org/en/downloads/branches/) (EOL) in a month.
+It didn't make sense to still support it.
+
+We want further than that, given the opportunity that we have with Hanami 2 to "start fresh" with the Ruby versions to support.
+We opted for taking 2.7 out as well.
+
+There are a few inconsistencies that have been fixed in Ruby 3.0 and we want to take advantage of this.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.alpha6
+- `hanami-cli` v2.0.0.alpha6
+- `hanami-view` v2.0.0.alpha6
+- `hanami-controller` v2.0.0.alpha6
+- `hanami-router` v2.0.0.alpha6
+- `hanami-utils` v2.0.0.alpha6
+
+## How can I try it?
+
+You can check out our [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template), which is up to date with this latest release and ready for you to use as the starting point for your own app.
+
+Weβd really love for you to give the tires a good kick for this release in particular: the more real-world testing we can have of our code loading changes, the better!
+
+## Whatβs coming next?
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this release, and weβre looking forward to checking in with you again next month. ππ»ββοΈπΈ
diff --git a/source/blog/2022-02-10-announcing-hanami-200alpha6/cover.jpg b/source/blog/2022-02-10-announcing-hanami-200alpha6/cover.jpg
new file mode 100644
index 000000000..5e46f4f63
Binary files /dev/null and b/source/blog/2022-02-10-announcing-hanami-200alpha6/cover.jpg differ
diff --git a/source/blog/2022-03-08-announcing-hanami-200alpha7.html.markdown b/source/blog/2022-03-08-announcing-hanami-200alpha7.html.markdown
new file mode 100644
index 000000000..d122719dc
--- /dev/null
+++ b/source/blog/2022-03-08-announcing-hanami-200alpha7.html.markdown
@@ -0,0 +1,163 @@
+---
+title: Announcing Hanami v2.0.0.alpha7
+date: 2022-03-08 12:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Concrete slice classes, consistent action and view class structures
+---
+
+Hi again, Hanami friends, weβre happy to be back this month to share the release of Hanami 2.0.0.alpha7.
+
+Before we go further, we want to make it clear that **we stand with the people of Ukraine in the face of the senseless, horrific attacks on their homeland by the Russian military.**
+
+We stand with all victims of this war: all the people who didnβt want this war, but are now directly or indirectly impacted. People who have lost their lives, their friends, their hopes. People who have had to escape their country because there is no future left for them. **We stand for people, not for flags.**
+
+If you can, [**please donate to support Ukrainians in this time of need**](https://razomforukraine.org).
+
+At very least, take the time to [read this perspective](https://zverok.space/blog/2022-03-03-WAR.html) from our Ruby friend Victor βzverokβ Shepelev, who is currently sheltering in the heavily bombarded Kharkiv, Ukraine, with his family. Victor should be spreading his Ruby magic, not dodging missiles.
+
+As for this Hanami alpha release: it contains improvements to slice configuration, as well as the action and view class structure within generated applications.
+
+## Slice configuration via concrete classes
+
+You can now configure your slices by creating concrete classes for each slice in `config/slices/`:
+
+```ruby
+# config/slices/main.rb:
+
+module Main
+ class Slice < Hanami::Slice
+ # slice config here
+ end
+end
+```
+
+The application-level `config.slice(slice_name, &block)` setting has been removed in favour of these classes, which provide much a clearer place for configuration.
+
+As of this release, you can use the slice classes to configure your slice imports:
+
+```ruby
+# config/slices/main.rb:
+
+module Main
+ class Slice < Hanami::Slice
+ # Import all exported components from "search" slice
+ import from: :search
+ end
+end
+```
+
+As well as particular components to export:
+
+```ruby
+# config/slices/search.rb:
+
+module Search
+ class Slice < Hanami::Slice
+ # Export the "index_entity" component only
+ export ["index_entity"]
+ end
+end
+```
+
+Hanami slices use dry-system to manage their internal container of components. Hanami does all the work to configure this container to work according to framework conventions as well as your own specific application configuration. However, for advanced cases, you can also directly configure the sliceβs container using `prepare_container` on the slice class:
+
+```ruby
+# config/slices/search.rb:
+
+module Search
+ class Slice < Hanami::Slice
+ prepare_container do |container|
+ # `container` (a Dry::System::Container subclass) is available here with
+ # slice-specific configuration already applied
+ end
+ end
+end
+```
+
+Finally, for simple Hanami applications, you donβt need to worry about creating these classes yourself: the framework will generate them for you in the absence of matching files in `config/slices/`.
+
+## Application shutdown completeness
+
+`Hanami::Application` provides a three-stage boot lifecycle, consisting of `.prepare`, `.boot`, and `.shutdown` methods, with the latter two steps calling `start` and `stop` respectively on each of the applicationβs registered providers.
+
+As of this release, `Hanami::Slice` also exposes its own `.shutdown` method, and `Hanami::Application.shutdown` will also call `.shutdown` on all the registered slices.
+
+## Consistent action and view class structure
+
+As of this release weβve settled upon a consistent structure for the action and view classes within generated applications.
+
+For actions, for example, the following classes will be generated:
+
+- A single application-level base class, e.g. `MyApp::Action::Base` in `lib/my_app/action/base.rb`. This is where you would put any logic or configuration that should apply to every action across all slices within the application.
+- A base class for each slice, e.g. `Main::Action::Base` in `slices/main/lib/action/base.rb`, inheriting from the application-level base class. This is where you would put anything that should apply to all the actions only in the particular slice.
+- Every individual action class would then go into the `actions/` directory within the slice, e.g. `Main::Actions::Articles::Index` in `slices/main/actions/articles/index.rb`.
+
+For views, the structure is much the same, with `MyApp::View::Base` and `Main::View::Base` classes located within an identical structure.
+
+The rationale for this structure is that it provides a clear place for any code to live that serves as supporting βinfrastructureβ for your applicationβs actions and views: it can go right alongside those `Base` classes, in their own directories, clearly separated from the rest of your concrete actions and views.
+
+This isnβt an imagined requirement: in a standard Hanami 2 application, weβll already be generating additional classes for the view layer, such as a view context class (e.g. `Main::View::Context`) and a base view part class (e.g. `Main::View::Part`).
+
+This structure is intended to serve as a hint that your own application-level action and view behavior can and should be composed of their own single-responsibility classes as much as possible.
+
+To put it all together, the following represents the expected structure in generated applications:
+
+```
+lib/
+ app_template/
+ action/
+ base.rb # AppTemplate::Action::Base < Hanami::Action
+ view/
+ base.rb # AppTemplate::View::Base < Hanami::View
+ context.rb # AppTemplate::View::Context < Hanami::View::Context
+ part.rb # AppTemplate::View::Part < Hanami::View::Part
+slices/
+ main/
+ lib/
+ action/
+ base.rb # Main::Action::Base < AppTemplate::Action::Base
+ authentication.rb # Main::Action::Authentication (EXAMPLE APP-SPECIFIC MODULE)
+ view/
+ base.rb # Main::View::Base < AppTemplate::View::Base
+ context.rb # Main::View::Context < AppTemplate::View::Context
+ part.rb # Main::View::Part < AppTemplate::View::Part
+ part_builder.rb # Main::View::PartBuilder < Hanami::View::PartBuilder (OPTIONAL)
+ helpers/
+ authentication.rb # Main::View::Helpers::Authentication (EXAMPLE APP-SPECIFIC MODULE)
+ parts/
+ article.rb # Main::View::Parts::Article < Main::View::Part
+
+ actions/ # Concrete action classes (Main::Actions namespace)
+ views/ # Concrete view classes (Main::Views namespace)
+```
+
+Along with these changes, weβve also streamlined the default view templates directory, changing it from `web/templates/` to just `templates/`.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.alpha7 (with a follow-up fix available in 2.0.0.alpha7.1)
+- `hanami-cli` v2.0.0.alpha7
+- `hanami-view` v2.0.0.alpha7
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Tim Riley](https://github.com/timriley)
+- [Sean Collins](https://github.com/cllns)
+
+## How can I try it?
+
+You can check out our [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template), which is up to date with this latest release and ready for you to use as the starting point for your own app.
+
+## Whatβs coming next?
+
+Weβre currently hard at work on porting our view helpers to Hanami 2, which we hope to share with you in some form next month.
+
+Thank you as always for supporting Hanami!
diff --git a/source/blog/2022-03-08-announcing-hanami-200alpha7/cover.jpg b/source/blog/2022-03-08-announcing-hanami-200alpha7/cover.jpg
new file mode 100644
index 000000000..2af3e2bfa
Binary files /dev/null and b/source/blog/2022-03-08-announcing-hanami-200alpha7/cover.jpg differ
diff --git a/source/blog/2022-05-19-announcing-hanami-200alpha8.html.markdown b/source/blog/2022-05-19-announcing-hanami-200alpha8.html.markdown
new file mode 100644
index 000000000..8a78b5f5a
--- /dev/null
+++ b/source/blog/2022-05-19-announcing-hanami-200alpha8.html.markdown
@@ -0,0 +1,96 @@
+---
+title: Announcing Hanami v2.0.0.alpha8
+date: 2022-05-19 12:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ New base action and view classes, and a few fixes
+---
+
+After a monthβs break, weβre back with another Hanami 2.0.0 alpha release for you all!
+
+This release includes new base action and view classes, plus a few small fixes.
+
+## New base action and view classes
+
+This release includes new base classes for actions and views that integrate with their surrounding Hanami application: `Hanami::Application::Action`, `Hanami::Application::View`, and `Hanami::Application::View::Context`. Your base classes should now look like this:
+
+```ruby
+# lib/my_app/action/base.rb:
+
+require "hanami/application/action"
+
+module MyApp
+ module Action
+ class Base < Hanami::Application::Action
+ end
+ end
+end
+```
+
+```ruby
+# lib/my_app/view/base.rb:
+
+require "hanami/application/view"
+
+module MyApp
+ module View
+ class Base < Hanami::Application::View
+ end
+ end
+end
+```
+
+```ruby
+# lib/my_app/view/context.rb:
+
+require "hanami/application/view/context"
+
+module MyApp
+ module View
+ class Context < Hanami::Application::View::Context
+ end
+ end
+end
+```
+
+Our current [application template](https://github.com/hanami/hanami-2-application-template) has been updated to use these new classes.
+
+Weβve also relocated the code for these classes from hanami-controller and hanami-view into the hanami gem itself, which will help us maintain the best possible integrated experience as we work towards 2.0.0 and beyond.
+
+Any supporting code for these integrated classes is conditionally loaded based on the presence of their counterpart gems (hanami-controller and hanami-view), so you can continue to pare back the framework to suit different needs by removing hanami-controller and/or hanami-view from your applicationβs `Gemfile`.
+
+## A few small fixes
+
+Thanks very much to our contributors, this release also includes a few small fixes:
+
+- `hanami db` CLI commands work again
+- Action classes with an already-halted response will no longer attempt to render their automatically paired view
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.alpha8
+- `hanami-cli` v2.0.0.alpha8 (with a follow-up fix available in 2.0.0.alpha8.1)
+- `hanami-controller` v2.0.0.alpha8
+- `hanami-view` v2.0.0.alpha8
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Andrew Croome](https://github.com/andrewcroome)
+- [Lucas Mendelowski](https://github.com/lcmen)
+- [Tim Riley](https://github.com/timriley)
+
+## How can I try it?
+
+You can check out our [Hanami 2 application template](https://github.com/hanami/hanami-2-application-template), which is up to date with this latest release and ready for you to use as the starting point for your own app.
+
+## Whatβs coming next?
+
+Weβre still working away at porting our view helpers to Hanami 2, which we hope to share with you in some form next month.
+
+Thank you as always for supporting Hanami!
diff --git a/source/blog/2022-05-19-announcing-hanami-200alpha8/cover.jpg b/source/blog/2022-05-19-announcing-hanami-200alpha8/cover.jpg
new file mode 100644
index 000000000..5e46f4f63
Binary files /dev/null and b/source/blog/2022-05-19-announcing-hanami-200alpha8/cover.jpg differ
diff --git a/source/blog/2022-07-20-announcing-hanami-200beta1.html.markdown b/source/blog/2022-07-20-announcing-hanami-200beta1.html.markdown
new file mode 100644
index 000000000..62ef64515
--- /dev/null
+++ b/source/blog/2022-07-20-announcing-hanami-200beta1.html.markdown
@@ -0,0 +1,133 @@
+---
+title: Announcing Hanami v2.0.0.beta1
+date: 2022-07-20 07:54:53 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Hanami 2 first beta: app-centric revolution & CLI. What to expect in 2.0 and 2.1.
+---
+
+Hello Hanami community! Weβre thrilled to announce the release of Hanami 2.0.0.beta1!
+
+## App-centric revolution
+
+With this release, weβve revolutionized the Hanami app structure: the **`app/` directory is the primary home for your code**, and **slices are now optional**.
+
+βWhat's a slice?,β you may ask! Think of slices as distinct modules of your application. A typical case is to use slices to separate your business domains (e.g. billing, accounting, admin). For our earlier 2.0 alpha releases, slices were the only way to build Hanami apps, which presupposed you wanted a full modular monolith composed of multiple domains.
+
+With this change, you can just as easily build small services with Hanami, with minimal ceremony.
+
+Letβs dissect a newly generated application (this one being named βBookshelfβ):
+
+- `app/` is home for your application code
+- `app/actions/` holds your actions and `app/action.rb`, with `Bookshelf::Action` as their superclass
+- `config/app.rb` defines your application (`Bookshelf::App`) and its configuration
+- `config/settings.rb` defines your appβs settings, such as the database URL
+- `config/routes.rb` defines your appβs HTTP routes
+- `lib/` is the home for any general purpose code used by your application code
+- `lib/bookshelf/types.rb` defines your custom Ruby data types (using the dry-types gem)
+- `lib/tasks/` is there for any custom Rake tasks
+- `spec/` holds your tests (using RSpec)
+- `spec/requests/` holds your HTTP integration tests (using the rack-test gem)
+
+```
+β‘ tree .
+.
+βββ Gemfile
+βββ Gemfile.lock
+βββ README.md
+βββ Rakefile
+βββ app
+βΒ Β βββ action.rb
+βΒ Β βββ actions
+βββ config
+βΒ Β βββ app.rb
+βΒ Β βββ routes.rb
+βΒ Β βββ settings.rb
+βββ config.ru
+βββ lib
+βΒ Β βββ bookshelf
+βΒ Β βΒ Β βββ types.rb
+βΒ Β βββ tasks
+βββ spec
+ βββ requests
+ βΒ Β βββ root_spec.rb
+ βββ spec_helper.rb
+ βββ support
+ βββ requests.rb
+ βββ rspec.rb
+
+9 directories, 14 files
+```
+
+**Simple. In the spirit of Hanami.**
+
+## CLI
+
+This first beta comes with new CLI commands:
+
+- `hanami new` to generate a new application
+- `hanami server` to start the HTTP server (Puma)
+- `hanami routes` to print application routes
+
+Remember, `hanami --help`, is also your friend π.
+
+## Hanami 2.0 & 2.1
+
+Some of you may have noticed in the previous section we didn't mention views. Where have the views gone?
+
+We want to release Hanami 2 stable as soon as possible, so we decided to split the remaining scope across Hanami 2.0 and 2.1 releases.
+
+### Hanami 2.0
+
+The roadmap until 2.0 is straightforward: solidify the app structure as presented above. We plan to add more commands to CLI code generators, support code reloading, and write documentation.
+
+That's it!
+
+This way you can learn Hanami 2 by building apps (hint: this would be great for API apps, the router is _really_ fast).
+
+### Hanami 2.1
+
+For this release, things will look complete from a full stack web framework perspective. Hanami apps will support views, helpers, assets, and persistence (based on [rom-rb](https://rom-rb.org)).
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.beta1
+- `hanami-rspec` v3.11.0.beta1 (it follows RSpecβs versioning)
+- `hanami-cli` v2.0.0.beta1
+- `hanami-controller` v2.0.0.beta1
+- `hanami-router` v2.0.0.beta1
+- `hanami-validations` v2.0.0.beta1
+- `hanami-utils` v2.0.0.beta1
+
+For specific changes from the last alpha release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```
+β‘ gem install hanami --pre
+β‘ hanami new bookshelf
+β‘ cd bookshelf
+β‘ bundle exec hanami --help
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Andrew Croome](https://github.com/andrewcroome)
+- [Benjamin Klotz](https://github.com/tak1n)
+- [Luca Guidi](https://github.com/jodosha)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Narinda Reeders](https://github.com/narinda)
+- [Peter Solnica](https://github.com/solnic)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+We canβt wait to hear from you about this release, and weβre looking forward to checking in with you again soon. πΈ
diff --git a/source/blog/2022-07-20-announcing-hanami-200beta1/cover.jpg b/source/blog/2022-07-20-announcing-hanami-200beta1/cover.jpg
new file mode 100644
index 000000000..9ece9fac1
Binary files /dev/null and b/source/blog/2022-07-20-announcing-hanami-200beta1/cover.jpg differ
diff --git a/source/blog/2022-08-16-announcing-hanami-200beta2.html.markdown b/source/blog/2022-08-16-announcing-hanami-200beta2.html.markdown
new file mode 100644
index 000000000..5a3e0ca24
--- /dev/null
+++ b/source/blog/2022-08-16-announcing-hanami-200beta2.html.markdown
@@ -0,0 +1,98 @@
+---
+title: Announcing Hanami v2.0.0.beta2
+date: 2022-08-16 13:30:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Slice and action generators, middlwares inspection, and conditional slice loading
+---
+
+Hello again, friends! Weβre excited to share our release of Hanami 2.0.0.beta2!
+
+## Slice and action generators
+
+Last month we reintroduced the `hanami new` app generator, and this time around weβre happy to add another couple of generators.
+
+`hanami generate slice` will generate a new slice into `slices/`. Right now it gives you a base action class and an `actions/` directory for your own actions.
+
+To create those actions, you can use `hanami generate action`. This generates action classes into `app/actions/` by default, but you can also use `--slice [slice_name]` to specify a particular slice as the target.
+
+## Middlewares inspection
+
+To go along with our `hanami routes` CLI command, weβve added `hanami middlewares`, which displays the middlewares youβve configured for your Hanami rack app. This will be useful for understanding the flow of requests through middleware stacks, especially for stacks with middleware active at particular route prefixes.
+
+For a new Hanami app with cookie sessions configured, itβll look like this:
+
+```
+> hanami middlewares
+
+/ Dry::Monitor::Rack::Middleware (instance)
+/ Rack::Session::Cookie
+```
+
+You can also provide `--with-arguments` to see the arguments provided for each middlware:
+
+```
+> hanami middlewares --with-arguments
+
+/ Dry::Monitor::Rack::Middleware (instance) args: []
+/ Rack::Session::Cookie args: [{:secret=>"abc123"}]
+```
+
+## Conditional slice loading
+
+Slices are one of the superpowers weβre introducing with Hanami 2: by organising your application logic into distinct slices, you can create a truly modular app structure. Today with beta2 weβre introducing conditional slice loading, which will allow you to take advantage of that modularity by loading different sets of slices for different deployed workloads.
+
+You can specify the slices to load with a new `config.slices` setting:
+
+```ruby
+# config/app.rb
+
+module AppName
+ class App < Hanami::App
+ config.slices = %w[blog shop]
+ end
+end
+```
+
+You can also populate this setting directly via an `HANAMI_SLICES` environment variable, using commas to separate the slice names, e.g. `HANAMI_SLICES=blog,shop`.
+
+Any slices not incuded in this list will be completely ignored: their slice class will not be loaded, nor any of their other Ruby source files; effectively, they will not exist.
+
+Specifying slices like this will **improve boot time and minimize memory usage** for specific workloads (imagine a job runner that needs only a single slice), as well as help ensure clean boundaries between your slices.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.beta2
+- `hanami-rspec` v3.11.0.beta2 (it follows RSpecβs versioning)
+- `hanami-cli` v2.0.0.beta2
+- `hanami-router` v2.0.0.beta2
+
+For specific changes from the last alpha release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```
+β‘ gem install hanami --pre
+β‘ hanami new bookshelf
+β‘ cd bookshelf
+β‘ bundle exec hanami --help
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Seb Wilgosz](https://github.com/swilgosz)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+We canβt wait to hear from you about this release, and weβre looking forward to checking in with you again soon. πΈ
diff --git a/source/blog/2022-08-16-announcing-hanami-200beta2/cover.jpg b/source/blog/2022-08-16-announcing-hanami-200beta2/cover.jpg
new file mode 100644
index 000000000..9ece9fac1
Binary files /dev/null and b/source/blog/2022-08-16-announcing-hanami-200beta2/cover.jpg differ
diff --git a/source/blog/2022-09-21-announcing-hanami-200beta3.html.markdown b/source/blog/2022-09-21-announcing-hanami-200beta3.html.markdown
new file mode 100644
index 000000000..c84f89810
--- /dev/null
+++ b/source/blog/2022-09-21-announcing-hanami-200beta3.html.markdown
@@ -0,0 +1,98 @@
+---
+title: Announcing Hanami v2.0.0.beta3
+date: 2022-09-21 14:17:23 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Code reloading, Puma support out of the box, routes simplification
+---
+
+Hello again, friends! Weβre excited to share our release of Hanami 2.0.0.beta3!
+
+## Code Reloading
+
+Hanami server and console now support code reloading.
+
+New apps are generated with `hanami-reloader` in `Gemfile` and with a new `Guardfile`.
+Code reloading for `hanami server` is based on `guard`.
+When the file system changes because of code edits, Guard restarts the Hanami server.
+
+In Hanami 1, we achieved code reloading with an "inside-the-framework" approach that turned to be problematic.
+With `hanami-reloader`, we implemented this "outside-the-framework" that has positive implications:
+
+- File system watching is delegated to Guard
+- Hanami is now free from code reloading awareness
+- Not bundling `hanami-reloader` (e.g. in production), eliminates automatically the code reloading logic
+- With `zeitwerk` and `dry-container` we achieved lazy boot of the app, resulting in **very fast code reloading**.
+
+Regarding the Hanami console, we reintroduced `reload` command to be invoked from the console to reload its context.
+
+## Puma
+
+New apps are generated with `puma` in `Gemfile` and with `config/puma.rb` configuration.
+
+## Routes simplification
+
+The routes definition in `config/routes.rb` looks simpler with the elimination of `define` wrapper.
+
+**Before**
+
+```ruby
+# frozen_string_literal: true
+
+module Bookshelf
+ class Routes < Hanami::Routes
+ define do
+ root { "Hello from Hanami" }
+ end
+ end
+end
+```
+
+**After**
+
+```ruby
+# frozen_string_literal: true
+
+module Bookshelf
+ class Routes < Hanami::Routes
+ root { "Hello from Hanami" }
+ end
+end
+```
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- `hanami` v2.0.0.beta3
+- `hanami-rspec` v3.11.0.beta3 (it follows RSpecβs versioning)
+- `hanami-cli` v2.0.0.beta3
+- `hanami-reloader` v1.0.0.beta3
+
+For specific changes from the last beta release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```
+β‘ gem install hanami --pre
+β‘ hanami new bookshelf
+β‘ cd bookshelf
+β‘ bundle exec hanami --help
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Tim Riley](https://github.com/timriley)
+- [Piotr Solnica](https://github.com/solnic)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+We canβt wait to hear from you about this release, and weβre looking forward to checking in with you again soon. πΈ
diff --git a/source/blog/2022-09-21-announcing-hanami-200beta3/cover.jpg b/source/blog/2022-09-21-announcing-hanami-200beta3/cover.jpg
new file mode 100644
index 000000000..9ece9fac1
Binary files /dev/null and b/source/blog/2022-09-21-announcing-hanami-200beta3/cover.jpg differ
diff --git a/source/blog/2022-10-24-announcing-hanami-200beta4.html.markdown b/source/blog/2022-10-24-announcing-hanami-200beta4.html.markdown
new file mode 100644
index 000000000..c48f2b4b0
--- /dev/null
+++ b/source/blog/2022-10-24-announcing-hanami-200beta4.html.markdown
@@ -0,0 +1,102 @@
+---
+title: Announcing Hanami v2.0.0.beta4
+date: 2022-10-24 13:15:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Our last beta! Improved Hanami::Action memory usage, simplified body parser config, and a whole lot of polish.
+---
+
+Hello again, friends! Weβre delighted to share the release of Hanami 2.0.0.beta4, the final release of our 2.0.0.beta series!
+
+## Improved memory performance for Hanami::Action
+
+Hanami::Action plays a key role in Hanami 2.0 apps, powering each of your HTTP endpoints. For this release weβve made big improvements to the memory impact of subclassing Hanami::Action, with a memory reduction of over 5x for each subclass. This will help your Hanami apps retain a slim footprint even as they grow in size.
+
+## Simplified body parser config
+
+hanami-routerβs body parsers are the middleware that parse incoming request bodies to turn them into Ruby structures that you can use within your actions. Now configuring a body parser has become easier than ever. No more requires or class names, just provide the name for your parser:
+
+```ruby
+module MyApp
+ class App < Hanami::App
+ config.middleware.use :body_parser, :json
+ end
+end
+```
+
+You can now also specify custom action formats and matching body parser configuration both in the same place:
+
+```ruby
+module MyApp
+ class App < Hanami::App
+ config.actions.format json: "application/json+scim"
+ config.middleware.use :body_parser, [json: "application/json+scim"]
+ end
+end
+```
+
+## And a whole lot of polish!
+
+Weβve spent much of this releaseβs development cycle getting everything as tidy as possible. Here are a few highlights:
+
+- Added helpful output and help messages to all `hanami` CLI commands
+- `hanami generate` now generates tests for slice-based components under `spec/slices/[slice_name]/`
+- `Hanami::Settings` subclasses have a nested dry-types `Types` module auto-generated, for easy type-checking of settings: refer to `Types` inside your settings class and itβll just work!
+- `Hanami::Settings#inspect` hides values to prevent leakage of sensitive data, with `#inspect_values` as a way to see everything
+- `request` and `response` objects inside Hanami::Action now share the same `session` and `flash` objects, ensuring all session changes are persisted regardless of how theyβre made
+- Accessing `session` and `flash` now raise a helpful error message if sessions are not configured
+- `Hanami.app.configuration` is now `.config`, to better reflect usage in natural language
+
+## 2.0.0 is coming!
+
+This is the very last of our betas! From here, we expect to make two more releases:
+
+- A 2.0.0.rc1 release candidate in two weeks
+- The final 2.0.0 release in another two weeks
+
+For these releases, weβll be focused on minor bug fixes only, plus documentation and the 1.0 releases of our dry-rb gem dependencies. Weβll also be releasing a preview of our 2.0.0 user guide before the rc1 release.
+
+All of this means you can look forward to a 2.0.0 release towards the end of November!
+
+Between now and then, we need your help: please take the chance to test Hanami 2.0! Pull down this beta and give things a go, and let us know if you hit any issues.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.0.0.beta4
+- hanami-router v2.0.0.beta4
+- hanami-controller v2.0.0.beta4
+- hanami-cli v2.0.0.beta4
+- hanami-reloader v1.0.0.beta4
+- hanami-rspec v3.11.0.beta4 (it follows RSpecβs versioning)
+
+For specific changes in this beta release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```
+β‘ gem install hanami --pre
+β‘ hanami new bookshelf
+β‘ cd bookshelf
+β‘ bundle exec hanami --help
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Sean Collins](https://github.com/cllns)
+- [Luca Guidi](https://github.com/jodosha)
+- [Benjamin Klotz](https://github.com/tak1n)
+- [Tim Riley](https://github.com/timriley)
+- [Peter Solnica](https://github.com/solnic)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+We canβt wait to hear from you about this release, and weβre looking forward to sharing another update with you very soon. πΈ
diff --git a/source/blog/2022-10-24-announcing-hanami-200beta4/cover.jpg b/source/blog/2022-10-24-announcing-hanami-200beta4/cover.jpg
new file mode 100644
index 000000000..9ece9fac1
Binary files /dev/null and b/source/blog/2022-10-24-announcing-hanami-200beta4/cover.jpg differ
diff --git a/source/blog/2022-11-08-announcing-hanami-200rc1.html.markdown b/source/blog/2022-11-08-announcing-hanami-200rc1.html.markdown
new file mode 100644
index 000000000..9d6162fd3
--- /dev/null
+++ b/source/blog/2022-11-08-announcing-hanami-200rc1.html.markdown
@@ -0,0 +1,90 @@
+---
+title: Announcing Hanami v2.0.0.rc1
+date: 2022-11-08 08:24:53 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ First Release Candidate! Preparing for the stable release, and sharing a preview of our updated guides.
+---
+
+Hello, folks!
+
+Weβre very close to the stable version of Hanami 2!
+We now consider Hanami 2 done.
+Todayβs Release Candidate (RC) 2.0.0.rc1 is hopefully the last step before we achieve this great milestone.
+
+## Small changes
+
+Weβve spent much of this releaseβs development cycle getting everything as tidy as possible. Here are a few highlights:
+
+- Allow Rack middleware to be mounted directly inside routing scopes and slice scopes
+- Introduce `Hanami::App.environment` (and `Hanami::Slice.environment`) to run setup code inside a particular environment only
+- Simplify assignment of response format: `response.format = :json` (was `response.format = format(:json)`)
+- Improve error messages for missing action classes
+- Remove duplicated `config.sessions` in favor of `config.actions.sessions`
+- Fix `hanami routes` inspection of nested named routes
+- Introduce `Hanami::Slice.stop` to properly shutdown the app and all slices
+- Expect/define nested slices to be within their parentβs namespace
+- Use Zeitwerk to autoload the `hanami` gemβs internal classes
+- Remove `Hanami::Logger` from `hanami-utils` in favor of `Dry::Logger` from the new `dry-logger` gem
+- Ensure `Hanami::Utils::String.underscore` replaces `"."` (dot character) to `"_"` (underscore)
+
+## 2.0.0 is coming!
+
+**Expect 2.0.0 in two weeks.**
+
+Since the last Hanami beta, weβve released stable 1.0.0 versions of (almost) all dry-rb gems. The remaining few will come within the next two weeks.
+
+This means that the Ruby ecosystem will soon have a complete set of modern, **stable** libraries and frameworks to build the next generation of applications.
+
+Between now and then, we need your help: please take the chance to test Hanami 2.0! Pull down this RC and give things a go, and let us know if you hit any issues.
+
+## User guide preview
+
+To help you with your testing, weβre very excited to share a preview of our
+[Hanami 2.0 Getting Started Guide](https://guides.hanamirb.org/v2.0/introduction/getting-started/)!
+
+This is still a work in progress, and we plan to finish it over the next two weeks. Many thanks to
+[Andrew Croome](http://github.com/andrewcroome) and [Seb Wilgosz](https://github.com/swilgosz) for putting this guide together.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.0.0.rc1
+- hanami-cli v2.0.0.rc1
+- hanami-controller v2.0.0.rc1
+- hanami-router v2.0.0.rc1
+- hanami-validations v2.0.0.rc1
+- hanami-utils v2.0.0.rc1
+- hanami-reloader v2.0.0.rc1 (it now follows Hanamiβs versioning)
+- hanami-rspec v2.0.0.rc1 (it now follows Hanamiβs versioning)
+
+For specific changes in this RC release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+β‘ gem install hanami --pre
+β‘ hanami new bookshelf
+β‘ cd bookshelf
+β‘ bundle exec hanami --help
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Tim Riley](https://github.com/timriley)
+- [Peter Solnica](https://github.com/solnic)
+- [Andrew Croome](https://github.com/andrewcroome)
+- [Benjamin Klotz](https://github.com/tak1n)
+- [Xavier Noria](https://github.com/fxn)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+We canβt wait to hear from you about this release candidate, and weβre looking forward to sharing another update with you in just two weeks! πΈ
diff --git a/source/blog/2022-11-08-announcing-hanami-200rc1/cover.jpg b/source/blog/2022-11-08-announcing-hanami-200rc1/cover.jpg
new file mode 100644
index 000000000..9ece9fac1
Binary files /dev/null and b/source/blog/2022-11-08-announcing-hanami-200rc1/cover.jpg differ
diff --git a/source/blog/2022-11-22-announcing-hanami-200.html.markdown b/source/blog/2022-11-22-announcing-hanami-200.html.markdown
new file mode 100644
index 000000000..5dce0b5f7
--- /dev/null
+++ b/source/blog/2022-11-22-announcing-hanami-200.html.markdown
@@ -0,0 +1,97 @@
+---
+title: "Hanami 2.0: Better, Faster, Stronger"
+date: 2022-11-22 12:10 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Hanami 2.0 opens a new chapter for the Ruby community.
+---
+
+After more than three years of work, Hanami 2.0 is here! With this release we enter a new phase of maturity for the framework, and open a new chapter for the Ruby community.
+
+**Hanami 2.0 is better, faster, stronger.**
+
+## Better
+
+Since the beginning weβve called Hanami a _modern web framework for Ruby_. These beginnings have given us a solid foundation for the journey to 2.0: our focus on **maintainability**, **testability**, and your ability to **scale your app** from a small service to a large monolith.
+
+For 2.0 weβve gone further. Weβve **listened** to our community, weβve **simplified and simplified again**, weβve **sought new approaches** for building apps, and weβve **dared to challenge the status quo.**
+
+In turn, **we want you to challenge yourself**. We want you to try something new, to experiment, to level up as an engineer. To dare to change, just as as we did. Without change, there is no challenge, and without challenge, there is no growth.
+
+### Whatβs better with 2.0?
+
+The core of Hanami 2.0 is now the `app/` directory. So familiar, yet so powerful. Here you can organize your code however you want, while still enjoying sensible defaults for common components. Then, as your app grows, you can take advantage of slices to separate your code into domains.
+
+Weβve stripped everything back to its essence. Your new app is now refreshingly simple:
+
+```ruby
+require "hanami"
+
+module Bookshelf
+ class App < Hanami::App
+ end
+end
+```
+
+Hanami 2.0 delivers a framework that is at once minimal and powerful:
+
+- The **new app core** offers advanced code loading capabilities centered around a container and components
+- **Code autoloading** helps you work with minimal fuss
+- New built-in **slices** offer gradual modularisation as your app grows
+- An **always-there dependencies mixin** helps you draw clearer connections between your appβs components
+- **Redesigned action classes** integrate seamlessly with your appβs business logic
+- **Type-safe app settings** with dotenv integration ensure your app has everything it needs in every environment
+- New **providers** manage the lifecycle of your appβs critical components and integrations
+- **Top to bottom modularity** enables you to build apps of all kinds, including non-web apps
+- Our **rewritten [getting started guide](https://guides.hanamirb.org/v2.0/introduction/getting-started/)** helps you get going with all of the above
+
+Thereβs a lot to dig into for each of these. **[Check out the Highlights of Hanami 2.0](https://discourse.hanamirb.org/t/highlights-of-hanami-2-0/728)** to see more, including code examples.
+
+## Faster
+
+Weβve completely rewritten our HTTP routing engine, with benchmarks showing it [outperforms nearly all others](https://hanamirb.org/blog/2020/02/26/introducing-hanami-api/).
+
+You will see actions served in **microseconds**:
+
+```
+[bookshelf] [INFO] [2022-11-22 09:48:41 +0100] GET 200 129Β΅s 127.0.0.1 / -
+```
+
+When using Hanami in development, **your app will boot and reload instantly** thanks to our smart code loading. No matter how big your app grows, your console will load in milliseconds, and your tests will stay snappy. **No more waiting!**
+
+## Stronger
+
+This release is **a triumph of indie development.** Our small team of volunteer developers have put years of effort towards this release, and weβve pulled it off!
+
+Weβve also joined forces with the [dry-rb](https://dry-rb.org/) team. Together weβve rebuilt Hanami on top of and around the dry-rb libraries. If youβve ever had an interest in dry-rb, Hanami 2.0 gives you a curated experience and your easiest possible onramp.
+
+Hanami 2.0 marks a **major moment for Ruby ecosystem diversity.** With this release weβre providing a distinct and compelling new vision for Ruby apps. With the backing of a compassionate and dedicated core team, you can feel confident Hanami will be here for the long run.
+
+Why donβt you take a look? Weβd love for you to join us!
+
+Youβre just a few commands away from building **better, faster, stronger apps**:
+
+```shell
+$ gem install hanami
+$ hanami new bookshelf
+$ cd bookshelf
+$ bundle exec hanami server
+```
+
+Thank you from the Core Team of [Luca Guidi](https://github.com/jodosha), [Peter Solnica](https://github.com/solnic) and [Tim Riley](https://github.com/timriley).
+
+Thank you also to these wonderful people for contributing to Hanami 2.0!
+
+- [Andrew Croome](https://github.com/andrewcroome)
+- [Benjamin Klotz](https://github.com/tak1n)
+- [Lucas Mendelowski](https://github.com/lcmen)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Narinda Reeders](https://github.com/narinda)
+- [Pat Allan](https://github.com/pat)
+- [Philip Arndt](https://github.com/parndt)
+- [Sean Collins](https://github.com/cllns)
+- [Xavier Noria](https://github.com/fxn)
+
+πΈ
diff --git a/source/blog/2022-11-22-announcing-hanami-200/cover.jpg b/source/blog/2022-11-22-announcing-hanami-200/cover.jpg
new file mode 100644
index 000000000..7dbc1f820
Binary files /dev/null and b/source/blog/2022-11-22-announcing-hanami-200/cover.jpg differ
diff --git a/source/blog/2022-12-06-hanami-201.html.markdown b/source/blog/2022-12-06-hanami-201.html.markdown
new file mode 100644
index 000000000..74299f84c
--- /dev/null
+++ b/source/blog/2022-12-06-hanami-201.html.markdown
@@ -0,0 +1,58 @@
+---
+title: "Hanami 2.0.1"
+date: 2022-12-06 07:59:05 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Hanami 2.0.1: small enhancements and bug fixes
+---
+
+Hello again, friends! Weβre excited to share our release of Hanami 2.0.1!
+
+It ships with small enhancements and minor bug fixes, after our [2.0.0 release](/blog/2022/11/22/announcing-hanami-200/).
+
+## Enhancements and Bug Fixes
+
+ * Ensure `Content-Security-Policy` HTTP response header to be returned as a single line
+ * Ensure to load `.env` files during CLI commands execution
+ * Ensure `hanami server` to respect HTTP port used in `.env` or the value given as CLI argument (`--port`)
+ * Ensure Rack events are on internal notifications system
+ * Return HTTP response header `Allow` when returning `405` HTTP status
+ * Introduce `Hanami::Middleware::BodyParser::FormParser` to parse multipart file upload
+ * Make `Hanami::Utils::Callbacks::Chain` and `Hanami::Utils::Callbacks::Callback` comparable via `#==` based on their contents, rather than their object identity
+
+## Released Gems
+
+ * `hanami` `2.0.1`
+ * `hanami-reloader` `2.0.1`
+ * `hanami-cli` `2.0.1`
+ * `hanami-router` `2.0.1`
+ * `hanami-utils` `2.0.1`
+
+## How To Upgrade
+
+How to upgrade from a Hanami app:
+
+```shell
+$ bundle update hanami-utils hanami-router hanami-cli hanami-reloader hanami
+```
+
+How to try Hanami for the first time:
+
+```shell
+$ gem install hanami
+$ hanami new bookshelf
+$ cd bookshelf
+$ bundle exec hanami server # visit http://localhost:2300
+```
+
+## Thank You
+
+Thank you also to these wonderful people for contributing to Hanami 2.0.1!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Tim Riley](https://github.com/timriley)
+- [Armin](https://github.com/wuarmin)
+
+πΈ
diff --git a/source/blog/2022-12-06-hanami-201/cover.jpg b/source/blog/2022-12-06-hanami-201/cover.jpg
new file mode 100644
index 000000000..3729f48b9
Binary files /dev/null and b/source/blog/2022-12-06-hanami-201/cover.jpg differ
diff --git a/source/blog/2022-12-25-hanami-202.html.markdown b/source/blog/2022-12-25-hanami-202.html.markdown
new file mode 100644
index 000000000..2597840be
--- /dev/null
+++ b/source/blog/2022-12-25-hanami-202.html.markdown
@@ -0,0 +1,44 @@
+---
+title: "Hanami 2.0.2"
+date: 2022-12-25 12:59:22 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Hanami 2.0.2: Official support for Ruby 3.2
+---
+
+Following Ruby tradition to release on Christmas, we want to contribute with our own gift: Hanami 2.0.2!
+
+## Released Gems
+
+ * `hanami` `2.0.2`
+ * `hanami-reloader` `2.0.2`
+ * `hanami-rspec` `2.0.1`
+ * `hanami-cli` `2.0.2`
+ * `hanami-controller` `2.0.1`
+ * `hanami-router` `2.0.2`
+ * `hanami-validations` `2.0.1`
+ * `hanami-utils` `2.0.2`
+
+## How To Upgrade
+
+How to upgrade from a Hanami app:
+
+```shell
+$ bundle update hanami-utils hanami-validations \
+ hanami-router hanami-controller \
+ hanami-cli hanami-rspec \
+ hanami-reloader hanami
+```
+
+How to try Hanami for the first time:
+
+```shell
+$ gem install hanami
+$ hanami new bookshelf
+$ cd bookshelf
+$ bundle exec hanami server # visit http://localhost:2300
+```
+
+πΈ
diff --git a/source/blog/2022-12-25-hanami-202/cover.jpg b/source/blog/2022-12-25-hanami-202/cover.jpg
new file mode 100644
index 000000000..effc479d7
Binary files /dev/null and b/source/blog/2022-12-25-hanami-202/cover.jpg differ
diff --git a/source/blog/2023-02-01-hanami-203.html.markdown b/source/blog/2023-02-01-hanami-203.html.markdown
new file mode 100644
index 000000000..860fb96a8
--- /dev/null
+++ b/source/blog/2023-02-01-hanami-203.html.markdown
@@ -0,0 +1,129 @@
+---
+title: "Hanami 2.0.3"
+date: 2023-02-01 07:59:05 UTC
+tags: announcements
+author: Luca Guidi
+image: true
+excerpt: >
+ Hanami v2.0.3: params pattern matching, HTTP statuses as symbols, small enhancements and bug fixes
+---
+
+Hello again, friends! New month, new Hanami release: v2.0.3!
+
+It ships with small enhancements and minor bug fixes.
+
+## Params Pattern Matching
+
+Pattern Matching on request params is helpful to expand values into local variables:
+
+```ruby
+# frozen_string_literal: true
+
+module MyApp
+ module Actions
+ module Graphql
+ class Show < MyApp::Action
+ # ...
+
+ def handle(req, res)
+ # ...
+
+ req.params => {query:, variables:}
+ res.body = schema.execute(query, variables:).to_json
+ end
+ end
+ end
+ end
+end
+```
+
+## HTTP Statuses as Symbols
+
+From now on it's possible to reference the HTTP statuses, not only via an `Integer`, but also with a `Symbol`.
+
+Check our guides, for the entire [list of allowed HTTP statuses](https://guides.hanamirb.org/v2.0/actions/status-codes/).
+
+```ruby
+# frozen_string_literal: true
+
+module MyApp
+ module Actions
+ module Account
+ class Show < MyApp::Action
+ def handle(req, res)
+ halt :unauthorized unless logged_in?
+ # ...
+ end
+ end
+ end
+ end
+end
+```
+
+```ruby
+# frozen_string_literal: true
+
+module MyApp
+ module Actions
+ module Account
+ class Update < MyApp::Action
+ def handle(req, res)
+ unless req.params.valid?
+ res.status = :unprocessable_entity
+ # ...
+ end
+ end
+ end
+ end
+ end
+end
+```
+
+## Enhancements and Bug Fixes
+
+ * Ensure to setup a logger in a non-default Hanami env
+ * Use production logger settings for non-default Hanami env
+ * Ensure action accepting the request with a custom MIME Type
+ * Fix error message for missing format (MIME Type)
+ * Allow slices to have a default for registrations directory
+ * Halting with an unknown HTTP code will raise a `Hanami::Action::UnknownHttpStatusError`
+ * Ensure to run automatically bundle gems when using `hanami new` on Windows
+ * Ensure to generate the correct action identifier in routes when using `hanami generate action` with deeply nested action name
+ * `Hanami::Utils::Blank.blank?` to check if the current object is non-nil
+
+## Released Gems
+
+ * `hanami` `2.0.3`
+ * `hanami-cli` `2.0.3`
+ * `hanami-controller` `2.0.2`
+ * `hanami-utils` `2.0.3`
+
+## How To Upgrade
+
+How to upgrade from a Hanami app:
+
+```shell
+$ bundle update hanami-utils hanami-controller hanami-cli hanami
+```
+
+How to try Hanami for the first time:
+
+```shell
+$ gem install hanami
+$ hanami new bookshelf
+$ cd bookshelf
+$ bundle exec hanami server # visit http://localhost:2300
+```
+
+## Thank You
+
+Thank you also to these wonderful people for contributing to Hanami 2.0.3!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Pat Allan](https://github.com/pat)
+- [Adam Lassek](https://github.com/alassek)
+- [R Gibim](https://github.com/Drowze)
+- [hi-tech-jazz](https://github.com/hi-tech-jazz)
+- [dsisnero](https://github.com/dsisnero)
+
+πΈ
diff --git a/source/blog/2023-02-01-hanami-203/cover.jpg b/source/blog/2023-02-01-hanami-203/cover.jpg
new file mode 100644
index 000000000..6bdbae04e
Binary files /dev/null and b/source/blog/2023-02-01-hanami-203/cover.jpg differ
diff --git a/source/blog/2023-06-29-hanami-210beta1.html.markdown b/source/blog/2023-06-29-hanami-210beta1.html.markdown
new file mode 100644
index 000000000..91b61907b
--- /dev/null
+++ b/source/blog/2023-06-29-hanami-210beta1.html.markdown
@@ -0,0 +1,151 @@
+---
+title: Hanami 2.1.0.beta1
+date: 2023-06-29 09:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Introducing hanami-view and sharing our plans for v2.1
+---
+
+Since the release of 2.0, weβve been hard at work completing our vision for full stack Hanami apps. Today weβre excited to advance our view layer and introduce hanami-view with the release of 2.1.0.beta1.
+
+Just like our actions, views are standalone, callable objects. They can work with their arguments and dependencies to prepare exposures to pass to a template for rendering:
+
+```ruby
+# app/views/posts/index.rb
+module MyApp
+ module Views
+ module Posts
+ class Index < MyApp::View
+ include Deps["posts_repo"]
+
+ expose :posts do |page:|
+ posts_repo.listing(page:)
+ end
+ end
+ end
+ end
+end
+```
+
+```html
+Posts
+
+<%= posts.each do |post| %>
+ <%= post.title %>
+<% end %>
+```
+
+Views are automatically paired with matching actions, so they're ready for you to render:
+
+```ruby
+# app/actions/posts/index.rb
+
+module MyApp
+ module Actions
+ module Posts
+ class Index < MyApp::Action
+ def handle(request, response)
+ request.params => {page:}
+
+ # view is a ready-to-go instance of MyApp::Views::Posts::Index
+ response.render(view, page:)
+ end
+ end
+ end
+ end
+end
+```
+
+Hanami views are built on top of [Tilt](https://github.com/jeremyevans/tilt), giving them support for a wide range of template engines. For HTML templates, we provide first-party support for ERB (using a brand new implementation for hanami-view), Haml and Slim.
+
+Hanami will generate matching views when you generate your actions with the `hanami generate action` command. You can also generate views directly via `hanami generate view`.
+
+Along with views, weβre also introducing a range of built-in helpers, giving you convenient ways to create forms and programatically generate HTML. You can also provide your own helpers inside a `Views::Helpers` module within each app and slice namespace.
+
+You can write your own helpers using natural, expressive Ruby, including straightforward yielding of blocks:
+
+```ruby
+# app/views/helpers.rb
+
+module MyApp
+ module Views
+ module Helpers
+ # Feel free to organise your helpers into submodules as appropriate
+
+ def warning_box
+ # `tag` is our built-in HTML builder helper
+ tag.div(class: "warning") do
+ # Yielding implicitly captures content from the block in the template
+ yield
+ end
+ end
+ end
+ end
+end
+```
+
+```html
+Posts
+
+<%= warning_box do %>
+ This section is under construction
+<% end %>
+```
+
+hanami-view is the successor to dry-view, a view system honed over many years of real-world use. Along with the above, it includes even more powerful tools for helping you build a clean and maintainable view layer, such as custom view parts and scopes.
+
+Weβre working on updating our getting started guide to include an introduction to views, and weβll release this as soon as its available.
+
+In the meantime, weβre making this 2.1 beta release so you can give views a try and make sure theyβre ready for prime time!
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.1.0.beta1
+- hanami-cli v2.1.0.beta1
+- hanami-controller v2.1.0.beta1
+- hanami-router v2.1.0.beta1
+- hanami-validations v2.1.0.beta1
+- hanami-utils v2.1.0.beta1
+- hanami-view v2.1.0.beta1
+- hanami-reloader v2.1.0.beta1
+- hanami-rspec v2.1.0.beta1
+- hanami-webconsole v2.1.0.beta1
+
+For specific changes in this beta release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami --help
+```
+
+## Whatβs next for 2.1?
+
+Alongside our work on views, weβve been preparing Hanamiβs front end assets support. This will be based on esbuild, will integrate seamlessly with our views, and even support you splitting your front end assets by slice.
+
+We plan to release this as hanami-assets in an upcoming Hanami v2.0.beta2 release. At this point, youβll be able to build Hanami apps with a complete front end.
+
+After a short testing period, weβll release all of these as 2.1.0.
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Tim Riley](https://github.com/timriley)
+- [dsinero](https://github.com/dsinero)
+- [Masanori Ohnishi](https://github.com/MasanoriOnishi)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+Weβre excited to be expanding the Hanami vision again, and we canβt wait to hear from you about this beta! πΈ
diff --git a/source/blog/2023-06-29-hanami-210beta1/cover.jpg b/source/blog/2023-06-29-hanami-210beta1/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2023-06-29-hanami-210beta1/cover.jpg differ
diff --git a/source/blog/2023-10-04-hanami-210beta2.html.markdown b/source/blog/2023-10-04-hanami-210beta2.html.markdown
new file mode 100644
index 000000000..90ef330f0
--- /dev/null
+++ b/source/blog/2023-10-04-hanami-210beta2.html.markdown
@@ -0,0 +1,124 @@
+---
+title: Hanami 2.1.0.beta2
+date: 2023-10-04 07:24 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Previewing front end assets for Hanami 2.1 and our new CLI command: hanami dev.
+---
+
+**Today weβre excited to release Hanami `v2.1.0.beta2` and share a preview of Hanamiβs front end assets experience.**
+
+## `hanami dev`
+
+It all starts with a new command: `hanami dev`.
+
+Running `hanami dev` starts the familiar Hanami web server alongside our new **front end assets watcher and compiler**. This is based on [esbuild](https://esbuild.github.io), and uses a [brand new plugin](https://github.com/hanami/assets-js) to make it aware of Hanamiβs app structure.
+
+Hanamiβs assets support now requires [Node.js](https://nodejs.org) and [npm](https://www.npmjs.com) to work.
+
+## App structure for assets
+
+Your assets live in `app/assets/`. JavaScript files live under `js/` and serve as your main entry points.
+
+Hereβs an example `app/assets/js/app.ts`:
+
+```ts
+import "../css/app.css";
+
+console.log("Hello from app.ts");
+```
+
+As you can see, [TypeScript](https://www.typescriptlang.org) support comes out of the box. Just run `npm install typescript --save-dev`.
+
+With your initial assets files in place, you can hop over to your view layout to include them:
+
+`app/views/layouts/app.html.erb`
+
+```erb
+
+
+
+
+
+ Bookshelf
+ <%= favicon %>
+ <%= css "app" %>
+
+
+ <%= yield %>
+ <%= js "app" %>
+
+
+```
+
+And with that, youβre done! Your app is now serving your custom styles and JavaScript behavior.
+
+## View helpers for assets
+
+We provide a [complete range of helpers](https://github.com/hanami/hanami/blob/965aa5aeb25b0a16b9c519866f14b4fa916d290a/lib/hanami/helpers/assets_helper.rb#L1) for working with your assets in various ways, including `js`, `css` (or their fuller equivalents, `javascript` and `stylesheet`) `asset_url`, `image` and more.
+
+## Assets for slices
+
+For users of Hanami slices, we have you covered too: assets can live within each slice, in `slices/[slice_name]/assets` directories that can take the same structure as the app-level assets.
+
+## CLI commands
+
+Along with the `hanami dev` command, you can also use the `hanami assets compile` and `hanami assets watch` commands directly.
+
+## We need your help!
+
+If youβve been waiting for the full stack Hanami experience, this beta release is a huge step forward.
+
+Since our assets support is brand new, we need your help! Weβd love you to give this a try with your favorite front end tools and packages, and [let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.1.0.beta2
+- hanami-reloader v2.1.0.beta2
+- hanami-webconsole v2.1.0.beta2
+- hanami-cli v2.1.0.beta2
+- hanami-assets v2.1.0.beta2
+- hanami-view v2.1.0.beta2
+- hanami-controller v2.1.0.beta2
+- hanami-assets v2.1.0-beta.2 (npm package)
+
+For specific changes in this beta release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install foreman
+> gem install hanami --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Whatβs next for 2.1?
+
+From here, weβll be working through the small number of βTodoβ items remaining on our [Hanami v2.1 project board](https://github.com/orgs/hanami/projects/2/views/1). These are mostly just polish and preparation tasks.
+
+Depending on what we learn from your testing and feedback, this means **the full 2.1 release may only be a matter of weeks away!** Weβll also be focusing on getting our docs ready to go as well, and weβll begin to release these as soon as they start to come together.
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Tim Riley](https://github.com/timriley)
+- [Philip Arndt](https://github.com/parndt)
+- [Ryan Bigg](https://github.com/radar)
+
+## Thank you
+
+Thank you as always for supporting Hanami!
+
+Weβre very excited to be nearing 2.1, and we canβt wait to hear from you about this beta! πΈ
+
+---
+
+**EDIT: We released `v2.1.0.beta2.1` because one Pull Request wasn't merged before the release. Sorry for the problem.**
diff --git a/source/blog/2023-10-04-hanami-210beta2/cover.jpg b/source/blog/2023-10-04-hanami-210beta2/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2023-10-04-hanami-210beta2/cover.jpg differ
diff --git a/source/blog/2023-11-01-hanami-210rc1.html.markdown b/source/blog/2023-11-01-hanami-210rc1.html.markdown
new file mode 100644
index 000000000..69df37e64
--- /dev/null
+++ b/source/blog/2023-11-01-hanami-210rc1.html.markdown
@@ -0,0 +1,140 @@
+---
+title: Hanami 2.1.0.rc1
+date: 2023-11-01 09:09 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ A stylish new welcome screen, next level assets flexibility, and our last stop before 2.1.0!
+---
+
+**Today weβre excited to release Hanami `v2.1.0.rc1`, the final stop before our stable 2.1.0 release!** This release brings a stylish new welcome experience, next level assets flexibility, and a range of view parts and helpers improvements. It is also our last stop before 2.1.0!
+
+## New welcome and error pages
+
+Your Hanami app now ships with a helpful and downright gorgeous first-run welcome screen, in both light and dark modes:
+
+![Welcome screen in light mode](/blog/2023/11/01/hanami-210rc1/welcome-light.png)
+
+![Welcome screen in dark mode](/blog/2023/11/01/hanami-210rc1/welcome-dark.png)
+
+This welcome screen displays whenever you boot the app without any routes.
+
+Along with this, weβre also giving your app elegant new designs for its production mode 404 and 500 error pages. These pages exist inside your apps `public/` directory, so you can customize these as required, though we wouldnβt blame you at all for rolling with these ones at least for a while:
+
+![Error 404 screen in light mode](/blog/2023/11/01/hanami-210rc1/error-404-light.png)
+
+![Error 404 screen in dark mode](/blog/2023/11/01/hanami-210rc1/error-404-dark.png)
+
+Weβd like to extend a **huge thanks** to [Aaron Moodie](https://github.com/aaronmoodie) for designing and building these screens.
+
+## Next level assets flexibility
+
+As of this release, your Hanami app will come with a new `config/assets.mjs` file. By default, it is nice and streamlined:
+
+```js
+import * as assets from "hanami-assets";
+
+await assets.run();
+```
+
+For many apps and their assets, this out of the box arrangement will be enough, and you shouldnβt need to touch this file.
+
+If you need something a little more, you can now use this file to configure and activate any number of [esbuild plugins](https://github.com/esbuild/community-plugins). For example, to use the [postcss plugin](https://github.com/karolis-sh/esbuild-postcss):
+
+```js
+import * as assets from "hanami-assets";
+import postcss from "esbuild-postcss";
+
+await assets.run({
+ esbuildOptionsFn: (args, esbuildOptions) => {
+ const plugins = [...esbuildOptions.plugins, postcss()];
+
+ return {
+ ...esbuildOptions,
+ plugins,
+ };
+ },
+});
+```
+
+With this `esbuildOptionsFn`, you can mix your own [esbuild options](https://esbuild.github.io), into ours, offering support for all kinds of assets setups.
+
+The `hanami assets` now also work via a single `"assets"` script managed within `package.json`, affording you even more flexibility if you need a completely exotic setup for your assets, but want to maintain our standard CLI experience for your developers.
+
+## Streamlined `hanami dev` via `bin/dev`
+
+New Hanami apps will now have their own `bin/dev` script, which will be run by the `hanami dev` CLI command.
+
+By default, this file auto-installs the [Foreman](https://github.com/ddollar/foreman) gem, so you can run your Hanami dev servers without any other setup.
+
+This file is yours to own and modify, so you can feel free to add any other dev server affordances here.
+
+## Parts and helper adjustments
+
+After beta2, we made some refinments to our assets helper names to minimise naming collisions in your views. The adjusted names are `javascript_tag`, `stylesheet_tag`, `favicon_tag`, `image_tag`, `video_tag` and `audio_tag`.
+
+In addition, helpers inside your view part classes are now contained inside a single `helpers` object, ensuring no collisions with the many method names that view parts forward to your appβs domain objects. Accessing a helper inside a view part now looks like this:
+
+```ruby
+module MyApp
+ module Views
+ module Parts
+ class Post
+ def title_header
+ helpers.tag.h1(title)
+ end
+ end
+ end
+ end
+end
+```
+
+Finally, we added a new `hanami generate part` CLI command, which will generate both a new part and a file for its unit tests (standalone testing of view behavior via parts is one of their best features!).
+
+Thanks very much to [Philip Arndt](https://github.com/parndt) for his field testing and feedback in this area.
+
+## We need your help!
+
+Our stable 2.1.0 release is just weeks away! We now consider 2.1.0 to be frozen, and we need your help to shake out any bugs.
+
+Since we introduced our assets support in 2.1.0.beta2 just two weeks ago, early feedback from our users has helped us deliver all the improvements above.
+
+You can help here too! Weβd love you to give this a try with your favorite front end tools and packages, and [let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.1.0.rc1
+- hanami-rspec v2.1.0.rc1
+- hanami-cli v2.1.0.rc1
+- hanami-assets v2.1.0.rc1
+- hanami-view v2.1.0.rc1
+- hanami-controller v2.1.0.rc1
+- hanami-assets v2.1.0-rc.1 (npm package)
+
+For specific changes in this beta release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Aaron Moodie](https://github.com/aaronmoodie)
+- [Luca Guidi](https://github.com/jodosha)
+- [PaweΕ ΕwiΔ
tkowski](https://github.com/katafrakt)
+- [Philip Arndt](https://github.com/parndt)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this release candidate! πΈ
diff --git a/source/blog/2023-11-01-hanami-210rc1/cover.jpg b/source/blog/2023-11-01-hanami-210rc1/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2023-11-01-hanami-210rc1/cover.jpg differ
diff --git a/source/blog/2023-11-01-hanami-210rc1/error-404-dark.png b/source/blog/2023-11-01-hanami-210rc1/error-404-dark.png
new file mode 100644
index 000000000..a22ea6621
Binary files /dev/null and b/source/blog/2023-11-01-hanami-210rc1/error-404-dark.png differ
diff --git a/source/blog/2023-11-01-hanami-210rc1/error-404-light.png b/source/blog/2023-11-01-hanami-210rc1/error-404-light.png
new file mode 100644
index 000000000..a1f741267
Binary files /dev/null and b/source/blog/2023-11-01-hanami-210rc1/error-404-light.png differ
diff --git a/source/blog/2023-11-01-hanami-210rc1/welcome-dark.png b/source/blog/2023-11-01-hanami-210rc1/welcome-dark.png
new file mode 100644
index 000000000..e1211bf74
Binary files /dev/null and b/source/blog/2023-11-01-hanami-210rc1/welcome-dark.png differ
diff --git a/source/blog/2023-11-01-hanami-210rc1/welcome-light.png b/source/blog/2023-11-01-hanami-210rc1/welcome-light.png
new file mode 100644
index 000000000..4df449a3a
Binary files /dev/null and b/source/blog/2023-11-01-hanami-210rc1/welcome-light.png differ
diff --git a/source/blog/2023-11-08-hanami-210rc2.html.markdown b/source/blog/2023-11-08-hanami-210rc2.html.markdown
new file mode 100644
index 000000000..957f0bfc1
--- /dev/null
+++ b/source/blog/2023-11-08-hanami-210rc2.html.markdown
@@ -0,0 +1,82 @@
+---
+title: Hanami 2.1.0.rc2
+date: 2023-11-08 08:19 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Some final fixes and polish, along with a preview of our guides.
+---
+
+Weβve had some very helpful testing and feedback since our 2.1.0.rc1 release last week, so today weβre happy to back with an rc2 release, bringing a range of fixes and polish. Weβre also happy to release a preview of our 2.1 guides!
+
+## Fixes
+
+We discovered a couple of blockers for people generating new apps. These are now fixed. `hanami new` will now generate:
+
+- The correct helpers in the default `app/templates/layouts/app.html.erb` layout.
+- The proper version string for prerelease versions of our hanami-assets package in `package.json`.
+
+In addition, detailed error messages (controlled via `config.render_detailed_errors`) will now default only show when the app is the development environment. Previously, they also showed in the test environment. This change ensures that error output will not accidentally trigger false positives in your tests.
+
+## Polish
+
+We now generate the `"type": "module"` [directive](https://nodejs.org/api/packages.html#type) in `package.json`, so front end JavaScript for new Hanami apps will now use [ES modules](https://nodejs.org/api/esm.html) by default. This allows our assets config at `config/assets.js` to use the conventional `.js` file extension, instead of `.mjs` as previously generated.
+
+Our RSpec support has been made friendlier for full stack apps, with [Capybara](https://github.com/teamcapybara/capybara) support now included by default. Our standard RSpec setup in `spec/support/rspec.rb` now includes code comments detailing the purpose of the various configs, making these easier to use or tailor to your preferences.
+
+The `hanami generate action` and `hanami generate part` CLI commands now accept a `--skip-tests` flag to skip test generation.
+
+## Guides
+
+Our guides for 2.1 are close to ready, so weβre happy to [share a preview](https://guides.hanamirb.org/v2.1/introduction/getting-started/) for you to check out.
+
+The guides include a full, test-driven walkthrough of building your first app, either as a full stack web app or an API. If youβve been interested in checking out Hanami 2.1, this will help you get started! Weβd love to hear your feedback.
+
+## We need your help!
+
+We expect to make our stable 2.1.0 release **just next week!** We consider 2.1.0 to be frozen, and we need your help to shake out any bugs.
+
+Weβd love you to give this release a try, especially for building views and using your favorite front end tools and packages. [Let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.1.0.rc2
+- hanami-reloader v2.1.0.rc2
+- hanami-rspec v2.1.0.rc2
+- hanami-webconsole v2.1.0.rc2
+- hanami-cli v2.1.0.rc2
+- hanami-assets v2.1.0.rc2
+- hanami-view v2.1.0.rc2
+- hanami-controller v2.1.0.rc2
+- hanami-router v2.1.0.rc2
+- hanami-validations v2.1.0.rc2
+- hanami-utils v2.1.0.rc2
+- hanami-assets v2.1.0-rc.2 (npm package)
+
+For specific changes in this release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> gem install hanami-cli --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Luca Guidi](https://github.com/jodosha)
+- [Sean Collins](https://github.com/cllns)
+- [Seb Wilgosz](https://github.com/swilgosz)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this release candidate! πΈ
diff --git a/source/blog/2023-11-08-hanami-210rc2/cover.jpg b/source/blog/2023-11-08-hanami-210rc2/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2023-11-08-hanami-210rc2/cover.jpg differ
diff --git a/source/blog/2024-02-16-hanami-210rc3.html.markdown b/source/blog/2024-02-16-hanami-210rc3.html.markdown
new file mode 100644
index 000000000..85e7ee3c2
--- /dev/null
+++ b/source/blog/2024-02-16-hanami-210rc3.html.markdown
@@ -0,0 +1,88 @@
+---
+title: Hanami 2.1.0.rc3
+date: 2024-02-16 11:21 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ A revised approach to assets, and 2.1.0 coming soon.
+---
+
+After our [last release candidate](/blog/2023/11/08/hanami-210rc2/), we discovered a few limitations in our approach to asset compilation. With the end-of-year break approaching, we decided to step back, look at things fresh, and find an approach that would serve as a solid foundation for the future.
+
+With 2.1.0.rc3, weβre happy to release this new approach!
+
+## Independent assets per slice
+
+Now when you run `hanami assets compile` or `hanami assets watch`, weβll fork and run a separate assets compilation process for each slice in your app containing assets.
+
+These assets will then be compiled into separate directories under `public/assets/`, each with their own manifest file: app assets compile into `public/assets/` (containing a`public/assets/assets.json` manifest), whereas e.g. an "admin" sliceβs assets compile into `public/assets/admin/` (containing `public/assets/admin/assets.json`).
+
+Each slice will then have access to its own assets only, either via the view helpers or direct access using the registered `"assets"` component.
+
+**With this, we now deliver the same separations for assets that Hanami offers for every other aspect of slices: complete independence.**
+
+Slices may now have their own `config/assets.js` file, allowing you to customize asset compilation on a slice-by-slice basis. Of course, if you donβt require this, a single top-level `config/assets.js` will still work for all slices.
+
+You also no longer require an `"scripts": {"assets": "..."}` entry within your `package.json`. Instead, the Hanami CLI will detect `config/assets.js` files wherever they exist and invoke them directly.
+
+If youβd like to learn more about this new approach, see [this detailed post on our forum](https://discourse.hanamirb.org/t/a-new-approach-to-assets-in-2-1-0-rc3/900).
+
+## Upgrading from rc2
+
+Once you upgrade from rc2, each slice will only have access to its own assets, and those assets will no longer be namespaced with the sliceβs name.
+
+For example, if you have an admin slice, you can change `stylesheet_tag("admin/app.css")` just `stylesheet_tag("app.css")`.
+
+Assets in the app are also isolated, and are accessible only within the app, and not any other slices.
+
+## We need your help!
+
+This is a fairly significant change to assets, and while weβre confident itβs the right move for Hanami, we still need your help to test this with your apps.
+
+Please give this release a try, especially for building views and using your favorite front end tools and packages. Check out our [new guides](https://guides.hanamirb.org/v2.1/introduction/getting-started/) for an introduction, and then [let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs next? 2.1.0!
+
+We want this to be our last release candidate. The next step here is 2.1.0.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.1.0.rc3
+- hanami-assets v2.1.0-rc.3 (npm package)
+- hanami-assets v2.1.0.rc3
+- hanami-cli v2.1.0.rc3
+- hanami-controller v2.1.0.rc3
+- hanami-reloader v2.1.0.rc3
+- hanami-router v2.1.0.rc3
+- hanami-rspec v2.1.0.rc3
+- hanami-utils v2.1.0.rc3
+- hanami-validations v2.1.0.rc3
+- hanami-view v2.1.0.rc3
+- hanami-webconsole v2.1.0.rc3
+
+For specific changes in this release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> gem install hanami-cli --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Nishiki (ι¦θ―)](https://github.com/nshki)
+- [Philip Arndt](https://github.com/parndt)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this release candidate! πΈ
diff --git a/source/blog/2024-02-16-hanami-210rc3/cover.jpg b/source/blog/2024-02-16-hanami-210rc3/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2024-02-16-hanami-210rc3/cover.jpg differ
diff --git a/source/blog/2024-02-27-hanami-210.html.markdown b/source/blog/2024-02-27-hanami-210.html.markdown
new file mode 100644
index 000000000..f00813abd
--- /dev/null
+++ b/source/blog/2024-02-27-hanami-210.html.markdown
@@ -0,0 +1,207 @@
+---
+title: "Hanami 2.1: Views that are a sight to see"
+date: 2024-02-27 13:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Introducing our view layer and front-end assets support.
+---
+
+After a year of work, Hanami 2.1 is here! This release introduces our view layer and front-end assets support, and brings Hanami a big step closer to our full stack vision.
+
+## It all starts with `hanami dev`
+
+Working on your appβs front-end now starts with a single new command: `hanami dev`.
+
+Running `hanami dev` starts the familiar Hanami web server alongside our new **front-end assets watcher and compiler**.
+
+From there, youβre ready to open `http://localhost:2300` and take in our gorgeous new welcome screen, in both light and dark mode.
+
+![Welcome screen in light mode](/blog/2024/02/27/hanami-210/welcome-light.png)
+
+![Welcome screen in dark mode](/blog/2024/02/27/hanami-210/welcome-dark.png)
+
+_Welcome (back!) to Hanami. Weβve been building something special for you!_
+
+## Youβll love our view on views
+
+To build your new front-end, you can start with views. Like actions, **Hanami views are standalone, callable objects**, bringing a new level of clarity and reusability to the view layer.
+
+```ruby
+# app/views/posts/index.rb
+module MyApp
+ module Views
+ module Posts
+ class Index < MyApp::View
+ include Deps["posts_repo"]
+
+ expose :posts do |page:|
+ posts_repo.listing(page:)
+ end
+ end
+ end
+ end
+end
+```
+
+**View exposures** explicitly prepare the values we pass to templates, and they work seamlessly with Hanamiβs Deps mixin, allowing your view to cleanly access other parts of your app as required.
+
+```erb
+Posts
+
+<%= posts.each do |post| %>
+ <%= post.title %>
+<% end %>
+```
+
+Hanami 2.1 delivers a **brand new ERB engine**, providing you a familiar template environment while also allowing for natural Ruby in view-focused methods, with a simple `yield` capturing nested template content, with no special handling required.
+
+Your views have access to **a library of familiar helpers**:
+
+```erb
+<%= form_for :post, routes.path(:create_post) do |f| %>
+ <%= f.label "title" %>
+ <%= f.text_field "title" %>
+<% end %>
+```
+
+You can write **your own helpers**, too:
+
+```ruby
+module MyApp
+ module Views
+ module Helpers
+ def warning_box
+ # tag is Hanami's built-in HTML builder helper
+ tag.div(class: "warning") do
+ yield # captures nested content in the template; so natural!
+ end
+ end
+ end
+ end
+end
+```
+
+On their own, helpers can become a bit of a mishmash, so Hanami provides **view parts** that encapsulate your view logic right alongside the value it relates to. They can even render their own partials! This keeps your templates simple and lets you use ordinary OO techniques to refactor and independently test your view code.
+
+```ruby
+module MyApp
+ module Views
+ module Parts
+ # Every post exposed from a view comes with these methods
+ class Post < MyApp::Views::Part
+ def title_link
+ helpers.tag.a(title, href: context.routes.path(:post, id:))
+ end
+
+ def feature_box
+ render("feature_box", title: title, text: teaser_text)
+ end
+ end
+ end
+ end
+end
+```
+
+```erb
+
+ <% posts.each do |post| %>
+
+ <%= post.title_link %>
+ <%= post.feature_box %>
+
+ <% end>
+
+```
+
+**Rendering views from actions is a breeze.** From the get go, actions render their matching view automatically, no extra work required. Once your views need certain input, you can also make that wiring clear:
+
+```ruby
+def handle(request, response)
+ response.render(view, id: request.params[:id])
+end
+```
+
+## Say hello to `app/assets/`
+
+With your views ready to go, itβs time to explore assets.
+
+Your assets live in `app/assets/`. JavaScript files live under `js/`, with `app` files serving as your entry points:
+
+```js
+import "../css/app.css";
+
+console.log("Hello from app.ts");
+```
+
+As you can see, [TypeScript](https://www.typescriptlang.org) works out of the box. Just run `npm install typescript`.
+
+## Your assets come fast and flexible
+
+**Hanami assets are powered by [esbuild](https://esbuild.github.io)**, giving you lightning quick build times.
+
+Modern front-end affordances are ready for you out of the box, no configuration required, with our standard assets config a picture of simplicity:
+
+```js
+import * as assets from "hanami-assets";
+
+await assets.run();
+```
+
+If you need more, you can have more! **Assets config can be gracefully extended** to provide advanced esbuild options or [take advantage of its many plugins](https://github.com/esbuild/community-plugins). A fully integrated [PostCSS](https://postcss.org), for example, is just a few lines away:
+
+```js
+import * as assets from "hanami-assets";
+import postcss from "esbuild-postcss";
+
+await assets.run({
+ esbuildOptionsFn: (args, esbuildOptions) => {
+ const plugins = [...esbuildOptions.plugins, postcss()];
+
+ return {
+ ...esbuildOptions,
+ plugins,
+ };
+ },
+});
+```
+
+## Slice it your way
+
+As first-class Hanami features, views and assets work great inside slices as well as your `app/`. Every slice can have its own `views/`, `templates/` and `assets/` directories, for your views, parts, helpers, assets and more.
+
+With Hanami we want to help you draw the right boundaries to support your appβs domain, and views are no different.
+
+## The view ahead looks bright
+
+With Hanami 2.1, we are continuing to deliver our vision for a fresh take for Ruby apps. Weβd love for you dive in and give our views and assets a try!
+
+Check out our updated [getting started guide](https://guides.hanamirb.org/v2.1/introduction/getting-started/) for your first steps in building a full stack Hanami app. Youβre only a few commands away:
+
+```shell
+$ gem install hanami
+$ hanami new my_app
+$ cd my_app
+$ bundle exec hanami dev
+$ open http://localhost:2300
+```
+
+With views and assets done, our next step is the persistence layer. You can look forward to hearing more about this later this year.
+
+_Thank you from [Tim Riley](https://github.com/timriley) and [Luca Guidi](https://github.com/jodosha)._
+
+Thank you also to these wonderful people for contributing to Hanami 2.1!
+
+- [Aaron Moodie](https://github.com/aaronmoodie)
+- [dsinero](https://github.com/dsinero)
+- [Konnor Rogers](https://github.com/KonnorRogers)
+- [Masanori Ohnishi](https://github.com/MasanoriOnishi)
+- [Nishiki (ι¦θ―)](https://github.com/nshki)
+- [Pat Allan](http://github.com/pat)
+- [PaweΕ ΕwiΔ
tkowski](https://github.com/katafrakt)
+- [Philip Arndt](https://github.com/parndt)
+- [Ryan Bigg](https://github.com/radar)
+- [Seb Wilgosz](https://github.com/swilgosz)
+
+πΈ
diff --git a/source/blog/2024-02-27-hanami-210/cover.jpg b/source/blog/2024-02-27-hanami-210/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2024-02-27-hanami-210/cover.jpg differ
diff --git a/source/blog/2024-02-27-hanami-210/welcome-dark.png b/source/blog/2024-02-27-hanami-210/welcome-dark.png
new file mode 100644
index 000000000..b506e4314
Binary files /dev/null and b/source/blog/2024-02-27-hanami-210/welcome-dark.png differ
diff --git a/source/blog/2024-02-27-hanami-210/welcome-light.png b/source/blog/2024-02-27-hanami-210/welcome-light.png
new file mode 100644
index 000000000..74053ed96
Binary files /dev/null and b/source/blog/2024-02-27-hanami-210/welcome-light.png differ
diff --git a/source/blog/2024-04-04-new-leadership-for-hanami.html.markdown b/source/blog/2024-04-04-new-leadership-for-hanami.html.markdown
new file mode 100644
index 000000000..9d0254421
--- /dev/null
+++ b/source/blog/2024-04-04-new-leadership-for-hanami.html.markdown
@@ -0,0 +1,17 @@
+---
+title: New leadership for Hanami
+date: 2024-04-04 09:15 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+
+---
+
+After 17 years dedicated to open source Ruby, Luca Guidi [has stepped down](https://discourse.hanamirb.org/t/stepping-down-from-hanami/933?u=jodosha) from the Hanami and [dry-rb](https://dry-rb.org) projects.
+
+In Lucaβs place, I will step up as Hanami project lead. I also remain a committed member of the dry-rb core team.
+
+As for Hanami, weβre continuing on the path weβve followed over the last few years. [2.1 is now out the door](/blog/2024/02/27/hanami-210/), and 2.2 is next. As we plan for this release, you can look forward to seeing updates [on our forum](https://discourse.hanamirb.org/).
+
+Iβd like to extend a heartfelt thank you to Luca for all his contributions to Hanami and Ruby. Collaborating with Luca has been a true pleasure for me, and Iβm very proud of what weβve been able to create together in Hanami 2. Iβm looking forward to extending this vision for Ruby apps in the years to come! β€οΈ
diff --git a/source/blog/2024-04-04-new-leadership-for-hanami/cover.jpg b/source/blog/2024-04-04-new-leadership-for-hanami/cover.jpg
new file mode 100644
index 000000000..4abcd06ef
Binary files /dev/null and b/source/blog/2024-04-04-new-leadership-for-hanami/cover.jpg differ
diff --git a/source/blog/2024-07-16-hanami-220beta1.html.markdown b/source/blog/2024-07-16-hanami-220beta1.html.markdown
new file mode 100644
index 000000000..cd6137681
--- /dev/null
+++ b/source/blog/2024-07-16-hanami-220beta1.html.markdown
@@ -0,0 +1,255 @@
+---
+title: Hanami 2.2.0.beta1
+date: 2024-07-16 12:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Weβre close to completing the full stack Hanami 2 vision. Introducing our database layer and operations.
+---
+
+Earlier this year we introduced our view layer with [Hanami 2.1](/blog/2024/02/27/hanami-210/). After some intensive months of work, weβre back again and ready to complete the stack! With todayβs release of Hanami 2.2.0.beta1, weβre delighted to offer you a preview of our database layer, as well our new tool for organising business logic.
+
+## Introducing our database layer
+
+Hanamiβs database layer is based on [Ruby Object Mapper](https://rom-rb.org) (ROM), a mature and flexible data persistence toolkit for Ruby.
+
+Our goal for Hanami 2.2 is to provide the worldβs best ROM experience, one that feels thoroughly at home within Hanami apps. We want to make it easy for you to get started and enjoy the benefits that come from your separating persistence logic from your business concerns. At the same time, we also want to make sure you can use any ROM feature without having to eject yourself from Hanamiβs standard integration.
+
+With 2.2, we believe weβve achieved this. Letβs take a look at how it has come togther.
+
+When you generate a new app, youβll have a ready-to-go `DATABASE_URL` set in your `.env`. Our default for new apps is SQLite, with Postgres also supported, and MySQL is coming soon.
+
+You can create a migration with `bundle exec hanami generate migration`, and fill it in:
+
+```ruby
+ROM::SQL.migration do
+ change do
+ create_table :posts do
+ primary_key :id
+ column :title, :text, null: false
+ end
+ end
+end
+```
+
+Now you can migrate your database with `hanami db migrate`.
+
+After this, you can generate a new relation: `hanami generate relation posts`. Relations describe your low-level data sources. Here, this means your database tables. Relations are also your place to add reusable, chainable methods that you can use as the building blocks for expressive, higher-level queries. Add something simple to get started:
+
+```ruby
+module MyApp
+ module Relations
+ class Posts < MyApp::DB::Relation
+ schema :posts, infer: true
+
+ use :pagination
+ per_page 20
+
+ def order_by_latest
+ order(self[:id].desc)
+ end
+ end
+ end
+end
+```
+
+Relations are the primary component of your appβs database layer. While you can interact with them directly, itβs better to build a repo. With repos, you get to build your very own persistence API, so you can better manage how your data is accessed across your app. You can build a post repo with `hanami generate repo posts`. Here you can define a method to return your latest posts, built from the methods in your relation:
+
+```ruby
+module MyApp
+ module Repos
+ class PostRepo < MyApp::DB::Repo
+ def latest(page:)
+ posts.order_by_latest.page(page).to_a
+ end
+ end
+ end
+end
+```
+
+You can include this repo as a dependency of any other class in your app, which is how you can access your data wherever you need. In a view, for example:
+
+```ruby
+module MyApp
+ module Views
+ module Posts
+ class Index < MyApp::View
+ include Deps["repos.post_repo"]
+
+ expose :posts do |page: 1|
+ post_repo.latest(page:)
+ end
+ end
+ end
+ end
+end
+```
+
+Repo methods return structs: plain old value objects, just data, with no live connection back to the database. This means you can be confident in passing them all around your app, knowing things like accidental n+1 queries are a thing of the past.
+
+You can customize these structs by creating your own classes. Make one for your posts with `hanami generate struct post`. Inside these classes, you can access any of the attributes selected in your repoβs corresponding database query.
+
+```ruby
+module MyApp
+ module Structs
+ class Post < MyApp::DB::Struct
+ def excited_title
+ "#{title}!"
+ end
+ end
+ end
+end
+```
+
+With relations, repos, structs and more, you now have a home for every piece of your data logic, and the foundation for a database layer that can evolve to meet even the most demanding needs.
+
+## Your DB is our command
+
+You can manage the full lifecycle of your database thanks to this complete set of new CLI commands:
+
+- `hanami db create`
+- `hanami db drop`
+- `hanami db migrate`
+- `hanami db prepare`
+- `hanami db seed`
+- `hanami db structure dump`
+- `hanami db structure load`
+- `hanami db version`
+
+## Slice it your way
+
+It wouldnβt be a new Hanami feature if it didnβt come with first-class support for [slices](https://guides.hanamirb.org/v2.2/app/slices/), our built-in tool for modularising apps.
+
+With Hanami 2.2βs new database layer, you can choose to:
+
+- Share a database, but have each slice provide their own relations, so they can choose how much of the database to expose (the default)
+- Use a dedicated database for certain slices (as easy as creating a `SLICE_NAME__DATABASE_URL` env var)
+- Share a single set of relations across all slices, for a simpler, blended development experience
+- Or any combination of the above!
+
+See [this forum post](https://discourse.hanamirb.org/t/integrating-rom-into-hanami-2-2/971) to learn more about these various slice formations. What weβve delivered in this beta matches exactly the proposal in this post.
+
+## Introducing operations
+
+With Hanami 2.2 weβre debuting [dry-operation](https://github.com/dry-rb/dry-operation). With dry-operation, you have a streamlined tool for organising your business logic into flexible, composable objects made from flows of internal steps.
+
+dry-operation is the long-awaited successor to the venerable [dry-transaction](http://dry-rb.org/gems/dry-transaction) gem, and Iβm deeply grateful to [Marc BusquΓ©](https://github.com/waiting-for-dev) for building it. Even though itβs not quite fully released, weβre including it as a preview via a GitHub source in your new appβs `Gemfile`.
+
+Creating an operation is as easy as `hanami generate operation posts.create_post`. Operations can be built from multiple steps, with each returning a `Result`:
+
+```ruby
+module MyApp
+ module Posts
+ class CreatePost < MyApp::Operation
+ include Deps["repos.post_repo"]
+
+ def call(attributes)
+ validation = step validate(attributes)
+
+ post = post_repo.create(validation.to_h)
+
+ Success(post)
+ end
+
+ private
+
+ def validate(attributes)
+ # Validate attributes here.
+
+ # Return a `Failure` and execution above will short-circuit
+ # Failure(errors: ["not valid"])
+
+ # Return a `Success` and execution will continue with the value unwrapped
+ # Success(attributes)
+ end
+ end
+ end
+end
+```
+
+Every operation returning a `Success` or `Failure` is great for consistency (every caller is required to consider both sides), but also for expressiveness. You can now turn to pattern matching on results in your actions, for example:
+
+```ruby
+module MyApp
+ module Actions
+ module Posts
+ class Create < MyApp::Action
+ include Deps["posts.create_post"]
+
+ def handle(request, response)
+ result = create_post.call(request.params[:post])
+
+ case result
+ in Success(post)
+ response.redirect_to routes.path(:post, post.id)
+ in Failure(validation)
+ response.render(view, validation:)
+ end
+ end
+ end
+ end
+ end
+end
+```
+
+Operations are natively integrated with Hanamiβs database layer, providing `transaction do ... end` to ensure database changes are written together, and that an intervening `Failure` will automatically abort the transaction.
+
+With operations built from flows of steps, but also themselves able to be chained into higher-level flows, you have a powerful new building block for business logic in your Hanami apps.
+
+## We need your help!
+
+This is a major step for Hanami, so we need your help with testing.
+
+Weβve already updated our [getting started guides](https://guides.hanamirb.org/v2.2/introduction/getting-started/) to walk you through your first Hanami 2.2 app, database layer included. Please give this a try, then [let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs next? A release candidate, then 2.2.0.
+
+We want this to be the one and only beta release for 2.2.
+
+[The work we have remaining](https://github.com/orgs/hanami/projects/6/views/1) is relatively minor, so our next step from here will be a release candidate, and your last chance for testing before 2.2.0 stable.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.2.0.beta1
+- hanami-assets v2.2.0-beta.1 (npm package)
+- hanami-assets v2.2.0.beta1
+- hanami-cli v2.2.0.beta1
+- hanami-controller v2.2.0.beta1
+- hanami-db v2.2.0.beta1
+- hanami-reloader v2.2.0.beta1
+- hanami-router v2.2.0.beta1
+- hanami-rspec v2.2.0.beta1
+- hanami-utils v2.2.0.beta1
+- hanami-validations v2.2.0.beta1
+- hanami-view v2.2.0.beta1
+- hanami-webconsole v2.2.0.beta1
+
+For specific changes in this release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Adam Lassek](https://github.com/alassek)
+- [Damian C. Rossney](https://github.com/dcr8898)
+- [Krzysztof](https://github.com/krzykamil)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [Sean Collins](https://github.com/cllns)
+- [Sven Schwyn](https://github.com/svoop)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this beta! πΈ
diff --git a/source/blog/2024-07-16-hanami-220beta1/cover.jpg b/source/blog/2024-07-16-hanami-220beta1/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2024-07-16-hanami-220beta1/cover.jpg differ
diff --git a/source/blog/2024-09-25-hanami-220beta2.html.markdown b/source/blog/2024-09-25-hanami-220beta2.html.markdown
new file mode 100644
index 000000000..39ab6996c
--- /dev/null
+++ b/source/blog/2024-09-25-hanami-220beta2.html.markdown
@@ -0,0 +1,185 @@
+---
+title: Hanami 2.2.0.beta2
+date: 2024-09-25 13:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Rounding out the database layer: MySQL, powerful multi-database support, plus full contracts in actions
+---
+
+Weβre back to round out the brand new database layer [we introduced](/blog/2024/07/16/hanami-220beta1/) in our previous beta release. This time around, weβre adding MySQL, introducing a powerful new way of working with multiple databases, and bringing you a little treat at the same time: full validation contract support in actions!
+
+## MySQL support
+
+Now you can generate a new Hanami app with `hanami new my_app --database=mysql` and have a ready-to-go MySQL-backed Hanami app! All `hanami db` commands (like `db prepare`, `db migrate`, etc.) have been updated to manage your MySQL database over the lifecycle of your app.
+
+## Multiple gateways
+
+With beta1, we introduced the idea of distinct databases per slice. Now with beta2, you can mix and match multiple databases within _any_ slice! This comes courtesy of ROMβs gateways, which you can now setup as part of Hanamiβs database layer.
+
+Gateways in ROM represent a connection to a distinct database. You can use them within your relations by declaring a `gateway`:
+
+```ruby
+module MyApp
+ module Relations
+ class Uploads < MyApp::DB::Relation
+ # Use the `uploads` table from the `:artifacts` gateway.
+ gateway :artifacts
+ schema :uploads, infer: true
+ end
+ end
+end
+```
+
+By using gateways via relations, you can have your database layer seamlessly work with data from multiple sources, all while maintaining a streamlined public interface via your repos.
+
+You can configure multiple gateways without any additional config. Just set an appropriately named ENV var:
+
+```
+# The standard :default gateway
+DATABASE_URL=sqlite://db/app.sqlite
+
+# An :artifacts gateway
+DATABASE_URL__ARTIFACTS=sqlite://db/artifacts.sqlite
+```
+
+You can also use ENV vars to set up gateways for slices too:
+
+```
+MY_SLICE__DATABASE_URL=sqlite://db/my_slice.sqlite
+MY_SLICE__DATABASE_URL__ARTIFACTS=sqlite://db/my_slice-artifacts.sqlite
+```
+
+For more advanced cases, you can configure gateways explicitly, inside your `:db` provider:
+
+```ruby
+Hanami.app.configure_provider :db do
+ # Explicitly configure a gateway
+ config.gateway :artifacts do |gw|
+ # If not configured, will still be filled from `ENV["DATABASE_URL__ARTIFACTS"]`
+ gw.database_url = "..."
+
+ # Specify an adapter to use
+ gw.adapter :yaml
+
+ # Or configure an adapter explicitly
+ gw.adapter :yaml do |a|
+ # You can call `a.plugin` here
+ # Or also `a.extension` if this is an `:sql` adapter
+ end
+ end
+
+ # Multiple gateways can be configured
+ config.gateway :another do |gw|
+ # ...
+ end
+end
+```
+
+All `hanami db` commands are multi-gateway-aware. By default, they will operate on all configured databases for an app. You can also target a specific gatewayβs database by passing the `--app --gateway=gw_name` or `--slice=slice_name --gateway=gw_name` arguments.
+
+You can also pass a `--gateway` argument to `hanami generate migration` to generate a migration for a specific gateway.
+
+For more detail on gateway configuration, [see this pull request](https://github.com/hanami/hanami/pull/1452).
+
+## ROM commands and mappers
+
+We also completed the last piece of ROM integration work: integrated [commands](https://rom-rb.org/learn/core/5.2/commands/) and [mappers](https://rom-rb.org/learn/core/5.2/mappers/). These are advanced components of ROM, and if you need them in a Hanami app, now you can place them in `app/db/commands/` and `app/db/mappers/` and theyβll be automatically registered.
+
+## Full validation contracts for actions
+
+By popular demand, weβve taken a little detour from our database work to implement support for full [dry-validation](http://dry-rb.org/gems/dry-validation/) contracts for your actions. Now you can use `contract` within an action class and access all the features of dry-validation, especially rules:
+
+```ruby
+module MyApp
+ module Actions
+ module SignUp
+ class Create < MyApp::Action
+ contract do
+ params do
+ required(:birth_date).filled(:date)
+ end
+
+ rule(:birth_date) do
+ if value < (Date.today << (12 * 18))
+ key.failure("you must be 18 years or older")
+ end
+ end
+ end
+ end
+ end
+ end
+end
+```
+
+You can also provide a `Dry::Validation::Contract` class directly, which is helpful if you want to share validation rules across actions as well as other domain objects:
+
+```ruby
+class Create < MyApp::Action
+ contract SignUp::Contract
+end
+```
+
+Or you can even inject a contract object as a dependency, which is useful if the contract itself has dependencies from elsewhere in your app:
+
+```ruby
+class Create < MyApp::Action
+ include Deps[contract: "sign_up.contract"]
+end
+```
+
+## We need your help!
+
+With this beta, weβre another step closer to 2.2.0 proper, so we need your help with testing, especially if youβre a MySQL user, or have a use case that could be served by our multi-gateway support.
+
+Weβve already updated our [getting started guides](https://guides.hanamirb.org/v2.2/introduction/getting-started/) to walk you through your first Hanami 2.2 app, database layer included. Please give this a try, then [let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs next? A release candidate, then 2.2.0.
+
+Our current goal is to have Hanami 2.2.0 ready by [RubyConf](https://rubyconf.org), where Sean Collins will be giving [an introductory workshop](https://rubyconf.org/schedule/) (Day 2, Salon A1).
+
+Between now and then, we plan to make one more release: a single release candidate, towards the end of October. Take a look at [our project board](https://github.com/orgs/hanami/projects/6/views/1) to see the work we have remaining.
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.2.0.beta2
+- hanami-assets v2.2.0-beta.2 (npm package)
+- hanami-assets v2.2.0.beta2
+- hanami-cli v2.2.0.beta2
+- hanami-controller v2.2.0.beta2
+- hanami-db v2.2.0.beta2
+- hanami-reloader v2.2.0.beta2
+- hanami-router v2.2.0.beta2
+- hanami-rspec v2.2.0.beta2
+- hanami-utils v2.2.0.beta2
+- hanami-validations v2.2.0.beta2
+- hanami-view v2.2.0.beta2
+- hanami-webconsole v2.2.0.beta2
+
+For specific changes in this release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Adam Lassek](https://github.com/alassek)
+- [Krzysztof Piotrowski](https://github.com/krzykamil)
+- [Kyle Plump](https://github.com/kyleplump) β congrats on your first contributions, Kyle!
+- [Sean Collins](https://github.com/cllns)
+- [Tim Riley](https://github.com/timriley)
+
+## Thank you
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this beta! πΈ
diff --git a/source/blog/2024-09-25-hanami-220beta2/cover.jpg b/source/blog/2024-09-25-hanami-220beta2/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2024-09-25-hanami-220beta2/cover.jpg differ
diff --git a/source/blog/2024-10-29-hanami-220rc1.html.markdown b/source/blog/2024-10-29-hanami-220rc1.html.markdown
new file mode 100644
index 000000000..0aa5640e0
--- /dev/null
+++ b/source/blog/2024-10-29-hanami-220rc1.html.markdown
@@ -0,0 +1,92 @@
+---
+title: Hanami 2.2.0.rc1
+date: 2024-10-29 12:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Last stop before 2.2.0.
+---
+
+Our work on Hanami 2.2 continues, and today weβre very happy to offer a release candidate. This is our last stop before 2.2.0, which we plan to release this time next week!
+
+In this release, weβve continued to refine our new database layer:
+
+- You can now configure gateways ([introduced in beta2](/blog/2024/09/25/hanami-220beta2/)) with a hash of `connection_options`.
+- Config from matching gateways in parent slices is applied to gateways in child slices, allowing you to configure shared gateways in one place only.
+- `Hanami::Struct` instances provide a convenient `#to_json` method.
+- A [DatabaseCleaner](https://github.com/DatabaseCleaner/database_cleaner) setup is generated in new apps, to keep your test database in a predictable state between RSpec tests.
+- When running `hanami db` CLI commands in development mode, they will automatically apply to your test database as well, to keep it in sync and ready for your tests.
+- A sample `config/db/seeds.rb` is generated in new apps.
+- The `db seed` CLI command prints a notice if it does not find expected seed files.
+- Generated migrations include a `change do` block, ready for your migration code.
+- The default database URL for MySQL databases works out of the box for MySQL as installed by [Homebrew](https://brew.sh).
+
+Weβve enhanced more of our CLI experience:
+
+- You can set the Hanami env for all CLI commands by passing an `--env` or `-e` option, which is much nicer than prefixing command with a `HANAMI_ENV=` environment variable (which still works, mind you).
+- The `generate action` and `generate slice` CLI commands provide a `--skip-route` option
+- `generate` subcommands are available only if the counterpart gem is bundled (e.g. `generate action` will only appear if you have hanami-controller bundled).
+- IRB is now the default engine for `hanami console`.
+
+Lastly, weβve been readying [dry-operation](https://github.com/dry-rb/dry-operation) for its debut:
+
+- Fixed an issue where failures were not handled correctly inside `transaction` blocks
+- Automatically integrate operations with the ROM setup available in Hanami apps, so `transaction` blocks are available with no boilerplate required.
+
+## We need your help!
+
+This is our last release before 2.2.0, so now more than ever, we need your help with testing, especially if you want to work with databases. With this release, we believe weβve now covered every essential aspect of database configuration and usage. Please put this to the test!
+
+Weβve already updated our [getting started guides](https://guides.hanamirb.org/v2.2/introduction/getting-started/) to walk you through your first Hanami 2.2 app, database layer included. Please give this a try, then [let us know how you go](https://discourse.hanamirb.org).
+
+## Whatβs next? 2.2.0.
+
+Weβre aiming to release 2.2.0 next week, and complete our epic journey towards the Hanami 2 full stack vision. Mark the date!
+
+## Whatβs included?
+
+Today weβre releasing the following gems:
+
+- hanami v2.2.0.rc1
+- hanami-assets v2.2.0-rc.1 (npm package)
+- hanami-assets v2.2.0.rc1
+- hanami-cli v2.2.0.rc1
+- hanami-controller v2.2.0.rc1
+- hanami-db v2.2.0.rc1
+- hanami-reloader v2.2.0.rc1
+- hanami-router v2.2.0.rc1
+- hanami-rspec v2.2.0.rc1
+- hanami-utils v2.2.0.rc1
+- hanami-validations v2.2.0.rc1
+- hanami-view v2.2.0.rc1
+- hanami-webconsole v2.2.0.rc1
+
+For specific changes in this release, please see each gemβs own CHANGELOG.
+
+## How can I try it?
+
+```shell
+> gem install hanami --pre
+> hanami new my_app
+> cd my_app
+> bundle exec hanami dev
+```
+
+## Contributors
+
+Thank you to these fine people for contributing to this release!
+
+- [Adam Lassek](https://github.com/alassek)
+- [Anderson Saunders](https://github.com/Andsbf) β congrats on your first contributions, Anderson!
+- [FranΓ§ois Beausoleil](https://github.com/francois) β congrats on your first contributions, FranΓ§ois!
+- [Krzysztof Piotrowski](https://github.com/krzykamil)
+- [Kyle Plump](https://github.com/kyleplump)
+- [Seb Wilgosz](https://github.com/swilgosz)
+- [Tim Riley](https://github.com/timriley)
+
+A special thank you also to [Ernesto Tagwerker](https://github.com/etagwerker) for making a DatabaseCleaner release for us, and [RΓ©my Coutable](https://github.com/rymai) for making a Guard release for us.
+
+## Thank you
+
+Thank you as always for supporting Hanami! We canβt wait to hear from you about this release! πΈ
diff --git a/source/blog/2024-10-29-hanami-220rc1/cover.jpg b/source/blog/2024-10-29-hanami-220rc1/cover.jpg
new file mode 100644
index 000000000..2e16786e1
Binary files /dev/null and b/source/blog/2024-10-29-hanami-220rc1/cover.jpg differ
diff --git a/source/blog/2024-11-05-hanami-220.html.markdown b/source/blog/2024-11-05-hanami-220.html.markdown
new file mode 100644
index 000000000..5c903868b
--- /dev/null
+++ b/source/blog/2024-11-05-hanami-220.html.markdown
@@ -0,0 +1,252 @@
+---
+title: "Hanami 2.2: Persistence pays off"
+date: 2024-11-05 10:45:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ With our new database layer and operations, the Hanami 2 vision is complete!
+---
+
+Two years ago, we [released Hanami 2.0](/blog/2022/11/22/announcing-hanami-200/), opening a new chapter for Hanami and our vision for Ruby apps.
+
+Earlier this year, we took another step and introduced our view layer [with Hanami 2.1](/blog/2024/02/27/hanami-210/).
+
+Today we complete the vision! We are thrilled to share Hanami 2.2 with you. With this release, we introduce a powerful new database layer and a brand new tool for organizing your business logic.
+
+## Persistence pays off: Hanamiβs new database layer
+
+Hanamiβs new database layer gives you **a clear home for every aspect of your database interactions**, along with **the means to build your own clean interface** for your appβs business layer to consume.
+
+When you generate a new app, youβll have a ready-to-go `DATABASE_URL` in your `.env`. Our default database for new apps is SQLite, with Postgres and MySQL also supported.
+
+You can create a migration with `bundle exec hanami generate migration`, and fill it in:
+
+```ruby
+ROM::SQL.migration do
+ change do
+ create_table :posts do
+ primary_key :id
+ column :title, :text, null: false
+ end
+ end
+end
+```
+
+Now you can migrate your database with `hanami db migrate`.
+
+After this, you can generate a new relation: `hanami generate relation posts`. **Relations describe your low-level data sources.** Here, this means your database tables. Relations are also your place to add reusable, chainable methods that you can use as the building blocks for expressive, higher-level queries. Add something simple to get started:
+
+```ruby
+module MyApp
+ module Relations
+ class Posts < MyApp::DB::Relation
+ schema :posts, infer: true
+
+ use :pagination
+ per_page 20
+
+ def order_by_latest
+ order(self[:id].desc)
+ end
+ end
+ end
+end
+```
+
+While you can interact with relations directly, itβs better to build a repo. **With repos, you get to build your very own database interface,** so you can better manage how your data is accessed across your app. You can build a post repo with `hanami generate repo posts`. Here you can define a method to return your latest posts, built using the methods in your relation:
+
+```ruby
+module MyApp
+ module Repos
+ class PostRepo < MyApp::DB::Repo
+ def latest(page:)
+ posts.order_by_latest.page(page).to_a
+ end
+ end
+ end
+end
+```
+
+**You can include repos as dependencies of any class in your app,** which is how you can access your data wherever you need. In a view, for example:
+
+```ruby
+module MyApp
+ module Views
+ module Posts
+ class Index < MyApp::View
+ include Deps["repos.post_repo"]
+
+ expose :posts do |page: 1|
+ post_repo.latest(page:)
+ end
+ end
+ end
+ end
+end
+```
+
+**Repo methods return structs: plain old value objects with no live connection back to the database.** This means you can be confident in passing them all around your app, knowing things like accidental n+1 queries are a thing of the past.
+
+You can optionally customize these structs by creating your own matching classes. Make one for your posts with `hanami generate struct post`. Inside these classes, you can access any of the attributes selected in your repoβs corresponding database query.
+
+```ruby
+module MyApp
+ module Structs
+ class Post < MyApp::DB::Struct
+ def excited_title
+ "#{title}!"
+ end
+ end
+ end
+end
+```
+
+**With relations, repos, structs and more, you now have a home for every piece of your data logic, and the foundation for a database layer that can evolve to meet even the most demanding needs.**
+
+Hanamiβs database capabilities come from [ROM](https://rom-rb.org) (Ruby Object Mapper), a mature and flexible data persistence toolkit for Ruby. With Hanami 2.2, we are proud to provide the worldβs very best ROM experience, one that feels thorouhgly at home within Hanami apps. We make it easy for you to get started and enjoy the benefits of a dedicated persistence layer, while making sure you can still use every ROM feature without ever having to eject yourself from our integration of ROM with Hanami.
+
+## Your DB is our command
+
+You can manage the full lifecycle of your database thanks to this complete set of new CLI commands:
+
+- `hanami db create`
+- `hanami db drop`
+- `hanami db migrate`
+- `hanami db prepare`
+- `hanami db seed`
+- `hanami db structure dump`
+- `hanami db structure load`
+- `hanami db version`
+
+## Slice it your way
+
+It wouldnβt be a new Hanami feature if it didnβt come with first-class support for [slices](https://guides.hanamirb.org/v2.2/app/slices/), our built-in tool for modularizing your apps.
+
+**You can choose your own mix of databases across your slices.** You can choose to:
+
+- Share a single database, but have each slice provide its own relations, so they can choose exactly how much of the database to expose. This is our default.
+- Use a dedicated database for certain slices. This is as easy as a `SLICE_NAME__DATABASE_URL` env var!
+- Connect to any number of _additional_ databases within your app or slice. This is as easy as creating a `SLICE_NAME__DATABASE_URL__GATEWAY_NAME` env var!
+- Adopt a simpler, blended development experience by sharing a single database and set of relations across all slices.
+- Or any combination of the above!
+
+## Smooth operations
+
+Along with Hanami 2.2, weβre excited to **debut the brand new [dry-operation 1.0](https://dry-rb.org/gems/dry-operation).** With dry-operation, you have a **streamlined tool for organizing your business logic into flexible, composable objects made from flows of internal steps.**
+
+Creating an operation is as easy as `hanami generate operation posts.create_post`. Operations can be built from multiple steps, with each returning a `Result`:
+
+```ruby
+module MyApp
+ module Posts
+ class CreatePost < MyApp::Operation
+ include Deps["repos.post_repo"]
+
+ def call(attributes)
+ validation = step validate(attributes)
+
+ post = post_repo.create(validation.to_h)
+
+ Success(post)
+ end
+
+ private
+
+ def validate(attributes)
+ # Validate attributes here.
+
+ # Return a `Failure` and execution above will short-circuit
+ # Failure(errors: ["not valid"])
+
+ # Return a `Success` and execution will continue with the value unwrapped
+ # Success(attributes)
+ end
+ end
+ end
+end
+```
+
+Every operation returning a `Success` or `Failure` is great for consistency (every caller must consider both sides), but also for expressiveness. You can now turn to pattern matching on results in your actions, for example:
+
+```ruby
+module MyApp
+ module Actions
+ module Posts
+ class Create < MyApp::Action
+ include Deps["posts.create_post"]
+
+ def handle(request, response)
+ result = create_post.call(request.params[:post])
+
+ case result
+ in Success(post)
+ response.redirect_to routes.path(:post, post.id)
+ in Failure(validation)
+ response.render(view, validation:)
+ end
+ end
+ end
+ end
+ end
+end
+```
+
+**Operations integrate with Hanamiβs databases**, providing `transaction do ... end` blocks to ensure database changes are written together, with any intervening `Failure` automatically rolling back the transaction.
+
+dry-operation is the long-awaited successor to the venerable [dry-transaction](http://dry-rb.org/gems/dry-transaction) gem, and Iβm deeply grateful to [Marc BusquΓ©](https://github.com/waiting-for-dev) for building it.
+
+dry-operation is a first class part of Hanami, but like the other parts of the framework, if you donβt need it, you can remove it. If youβd rather use another tool to organize your business logic, youβre welcome to remove `"dry-operation"` from your `Gemfile` and replace it with something else.
+
+## More up our sleeve
+
+Databases and operations may be the highlights, but Hanami 2.2 brings several other improvements:
+
+- Support for using full [dry-validation](https://dry-rb.org/gems/dry-validation) contracts inside actions for params validation. Just use `.contract` instead of `.params` in your action classes.
+- Specify the `HANAMI_ENV` via `--env` or `-e` options to any `hanami` CLI command.
+- A new `hanami generate component` command generates PORO classes anywhere within your app.
+- When creating a new file via `hanami generate`, redundant `.keep` files are automatically removed.
+- Add `--skip-route` flag to `hanami generate slice` and `hanami generate action` commands.
+- Switch to IRB as the default engine for `hanami console`. Thank you [IRB team](https://github.com/ruby/irb/graphs/contributors?from=28%2F10%2F2023) for your continual improvements!
+- Inside providers, you can now refer to the slice as `slice`, rather than `target`.
+- Properly handle routes with differing segment captures at the same location.
+- Various minor fixes to our form helpers.
+- Dropped support for Ruby 3.0.
+
+## Full stack Hanami is here today!
+
+**With Hanamiβs database layer and operations, our fresh, full stack vision for Ruby apps is now complete!** Weβd love for you to dive in and give it a try.
+
+Check out our updated [getting started guide](https://guides.hanamirb.org/v2.1/introduction/getting-started/) for your first steps in building a full stack, database-backed Hanami app. Youβre only a few commands away:
+
+```shell
+$ gem install hanami
+$ hanami new my_app
+$ cd my_app
+$ bundle exec hanami dev
+$ open http://localhost:2300
+```
+
+After this, weβd love to hear your feedback about this release. Come and join us over on [the community forum](https://discourse.hanamirb.org). Once youβre signed up, youβll be able to join us for chat as well as the regular forum discussions. Come say hi!
+
+_Thank you from [Tim Riley](https://github.com/timriley)._
+
+Thank you also to these amazing people for contributing to Hanami 2.2!
+
+- [Adam Lassek](https://github.com/alassek)
+- [Anderson Saunders](https://github.com/Andsbf)
+- [Chris Flipse](https://github.com/cflipse)
+- [Damian C. Rossney](https://github.com/dcr8898)
+- [François Beausoleil](https://github.com/francois)
+- [Krzysztof Piotrowski](https://github.com/krzykamil)
+- [Kyle Plump](https://github.com/kyleplump)
+- [Marc BusquΓ©](https://github.com/waiting-for-dev)
+- [PaweΕ ΕwiΔ
tkowski](https://github.com/katafrakt)
+- [Sean Collins](https://github.com/cllns)
+- [Seb Wilgosz](https://github.com/swilgosz)
+- [Sven Schwyn](https://github.com/svoop)
+- [Tom de Bruijn](https://github.com/tombruijn)
+
+Thanks especially to [Adam](https://github.com/alassek), [Sean](https://github.com/cllns) and [Marc](https://github.com/waiting-for-dev). I couldnβt have made this release without you.
+
+πΈ
diff --git a/source/blog/2024-11-05-hanami-220/cover.jpg b/source/blog/2024-11-05-hanami-220/cover.jpg
new file mode 100644
index 000000000..23765b3ac
Binary files /dev/null and b/source/blog/2024-11-05-hanami-220/cover.jpg differ
diff --git a/source/blog/2024-12-10-state-of-hanami-december-2024.html.markdown b/source/blog/2024-12-10-state-of-hanami-december-2024.html.markdown
new file mode 100644
index 000000000..681bf4834
--- /dev/null
+++ b/source/blog/2024-12-10-state-of-hanami-december-2024.html.markdown
@@ -0,0 +1,77 @@
+---
+title: State of Hanami, December 2024
+date: 2024-12-10 10:30:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+ Everything we did this year, and what weβre looking forward to in the next. A new kind of update!
+---
+
+Welcome to your first **State of Hanami** update! πΈ
+
+Thereβs plenty going on around Hanami. With these updates, I want to make it easy for everyone in the community to keep up. Weβll share our recent achievements, as well as our plans for whatβs coming next.
+
+Weβll bring you these updates twice a year. This one is special, though, because we get to cover all of 2024!
+
+## Two major releases
+
+2024 was a big year for Hanami. We made two major releases:
+
+- [Hanami 2.1](https://hanamirb.org/blog/2024/02/27/hanami-210/) in February, introducing our view layer and frontend assets support.
+- [Hanami 2.2](https://hanamirb.org/blog/2024/11/05/hanami-220/) in November, introducing our database layer as well as operations.
+
+Two years after we brought you [Hanami 2.0](https://hanamirb.org/blog/2022/11/22/announcing-hanami-200/), our vision for full stack Hanami apps is now complete! This is a watershed moment for Hanami. With 2.2, we give you every essential for building your apps, while providing ourselves a solid foundation for the future of the framework.
+
+## New leadership
+
+In April we managed [a smooth transition of project leadership](https://hanamirb.org/blog/2024/04/04/new-leadership-for-hanami/), with Luca Guidi retiring and myself taking on the role of lead. Iβm happy to be here!
+
+## An expanded contributor group
+
+This year we welcomed a number of folks to our contributors group:
+
+- [Sean Collins](https://github.com/cllns), a long-time Hanami team member who is back with a bang! Sean has worked a lot across our CLI, and has a great eye for the overall developer experience.
+- [Adam Lassek](https://github.com/alassek), one of the worldβs leading experts in both [dry-system](https://github.com/dry-rb/dry-system) and [ROM](https://rom-rb.org), as well as how we bring the two of them together in Hanami. We couldnβt have built our database layer in 2.2 without Adamβs help.
+- [Marc BusquΓ©](https://github.com/waiting-for-dev), who built [dry-operation](http://dry-rb.org/gems/dry-operation) from scratch for Hanami 2.2. This is a gem Iβve wanted to exist for years, and Iβm so excited itβs now part of our stack.
+- [Kyle Plump](https://github.com/kyleplump), who brings great energy and is ready to help with issues of all kinds.
+- [Aaron Moodie](https://github.com/aaronmoodie), the designer behind our [shiny new welcome screen](https://hanamirb.org/blog/2024/11/05/hanami-220/), and our soon-to-be shiny new website (more on this later!).
+
+Weβve also enjoyed continued help from users and contributors [PaweΕ ΕwiΔ
tkowski](https://github.com/katafrakt), [Sven Schwyn](https://github.com/svoop), [Pat Allan](https://github.com/pat), as well as [Damian C. Rossney](https://github.com/dcr8898) who brought us this [especially amazing router fix](https://github.com/hanami/router/pull/273).
+
+Thank you to these fine humans above, and to everyone else who has contributed to Hanami in 2024!
+
+To make contributions easier in the future, we plan to clarify what it means to join and be a part of Hanamiβs contributor group, and provide an easier onramp by curating a range of βgood first issuesβ across our repos.
+
+## Out in the world
+
+We took Hanami out into the world:
+
+- In April, I ran [Ruby in Common](https://rubyincommon.org) in Sydney, an experimental unconf for experimentally-minded Rubyists, and introduced Hanami as part of the proceedings.
+- In July, I spoke [at RedDotRubyConf](https://www.rubyvideo.dev/talks/livin-la-vida-hanami-red-dot-ruby-conference-2024) in Singapore.
+- In November, Sean gave an introductory workshop at [RubyConf](https://rubyconf.org) in Chicago. Sean will soon bring these teaching to you in the comfort of your own home: [sign up here](http://learnhanami.com)!
+- Also at RubyConf, I [represented Hanami](https://discourse.hanamirb.org/t/hanami-hack-day-at-rubyconf-2024/1051/2) at the hack day, [helping four new people](https://ruby.social/@hanami/113482901185245079) make their first contributions!
+
+## Plans for 2025
+
+As we enter 2025, weβll be working towards some new kinds of goals for Hanami. Weβve spent years focused on framework development to get to 2.2. Now that weβre here, we can direct our energy towards _sharing_ everything weβve built together!
+
+To this end, weβll enter the year with three major goals:
+
+- **Unify and relaunch our ecosystem.** Weβre going to merge Hanami with dry-rb and ROM. One group of gems, one group of maintainers, and one compelling collection of tools for Rubyists of all stripes. As part of this, weβll establish new branding, launch a new website, and resurrect our mailing list. Weβll also create an easier onramp for new contributors.
+- **Help our users be more successful with Hanami.** Weβll share more examples of how to build with Hanami, expand our docs, streamline Hanamiβs deployment story, and improve our developer experience wherever we can.
+- **Fundraise for sustainable maintenance.** Weβll work with businesses and individuals to establish at least one day per week of paid maintenance of Hanami, dry-rb and ROM. This is a small step for Hanami, but a giant leap for the long-term sustainability of our ecosystem.
+
+Weβll share more on each of these goals as we embark on them in earnest.
+
+## Join us!
+
+Thatβs your **State of Hanami** for December 2024! Thank you for reading. ππ»ββοΈ
+
+Iβm very proud of what weβve built together this year, and incredibly excited for everything weβre going to do next.
+
+Weβd love you to join us! We encourage you to try Hanami for your apps, contribute some code or writing, or even financially support our project.
+
+To get in touch with us, come [say hi on our forum](https://discourse.hanamirb.org) β here you join us for chat as well as long-form discussions.
+
+You can also keep up by [subscribing to our blog](https://hanamirb.org) or following us on [Mastodon](https://ruby.social/@hanami) or [Bluesky](https://bsky.app/profile/hanamirb.org). Youβll be the first to know as we make each new step in 2025.
diff --git a/source/blog/2024-12-10-state-of-hanami-december-2024/cover.jpg b/source/blog/2024-12-10-state-of-hanami-december-2024/cover.jpg
new file mode 100644
index 000000000..23765b3ac
Binary files /dev/null and b/source/blog/2024-12-10-state-of-hanami-december-2024/cover.jpg differ
diff --git a/source/blog/2024-12-12-a-new-chapter-for-dry-rb-rom.html.markdown b/source/blog/2024-12-12-a-new-chapter-for-dry-rb-rom.html.markdown
new file mode 100644
index 000000000..d906b6715
--- /dev/null
+++ b/source/blog/2024-12-12-a-new-chapter-for-dry-rb-rom.html.markdown
@@ -0,0 +1,27 @@
+---
+title: A new chapter for dry-rb and ROM
+date: 2024-12-12 10:00:00 UTC
+tags: announcements
+author: Tim Riley
+image: true
+excerpt: >
+
+---
+
+After 10 years working on [dry-rb](https://dry-rb.org/), and 15 years on DataMapper and now [Ruby Object Mapper](https://rom-rb.org/) (aka ROM), Peter Solnica [is retiring from the dry-rb and ROM core teams](https://solnic.dev/retiring-from-the-core-teams).
+
+Iβd like to extend my deepest thanks to Peter for all his contributions to Ruby open source software. As a co-founder of these projects, Peter has put thousands of hours into a body of work that has benefited the entire community and changed the way we think about Ruby.
+
+Peter, my time with you has been [one of the defining chapters](https://www.icelab.com.au/notes/my-past-and-future-ruby) of my Ruby life. Iβve cherished the opportunity to work and grow alongside you. Thank you for everything! β€οΈ
+
+So whatβs next for dry-rb and ROM? The work continues as usual. Iβm still a committed maintainer, along with fellow co-founder [Nikita Shilnikov](https://github.com/flash-gordon) as well as the Hanami team, which today numbers another six regular contributors.
+
+But weβre not going to stop at that. Weβre going to give these projects a real boost.
+
+[We will merge dry-rb and ROM with Hanami](https://hanamirb.org/blog/2024/12/10/state-of-hanami-december-2024/). One compelling toolkit for Rubyists of all stripes, now backed by a unified community and group of maintainers. This was a mutual vision of Peterβs and mine, and I am still very excited to make it happen.
+
+Bringing these projects together will take a few months. Weβll be sharing the details as we go, so make sure to follow us [here on our blog](https://hanamirb.org/blog/), or on [Mastodon](https://ruby.social/@hanami) or [Bluesky](https://bsky.app/profile/hanamirb.org).
+
+Our gems themselves will continue to work as always, so in the meantime you can continue to help us by using these gems in your apps, and sharing your feedback, issues and PRs. Weβd love to hear from you.
+
+Peter, thank you again for everything youβve given us, and hereβs to the next chapter for Hanami, dry-rb and ROM!
diff --git a/source/blog/2024-12-12-a-new-chapter-for-dry-rb-rom/cover.jpg b/source/blog/2024-12-12-a-new-chapter-for-dry-rb-rom/cover.jpg
new file mode 100644
index 000000000..23765b3ac
Binary files /dev/null and b/source/blog/2024-12-12-a-new-chapter-for-dry-rb-rom/cover.jpg differ
diff --git a/source/community.html.erb b/source/community.html.erb
index 6ab04146c..3e4848c79 100644
--- a/source/community.html.erb
+++ b/source/community.html.erb
@@ -9,42 +9,82 @@ title: Community
Hanami's official code repository is on Github. If you find any bugs, please report them by opening an issue. Also, pull requests are always welcome. We will get back to you as soon as possible.
github.com/hanami
+
+The Hanami Discourse forum is the best place for any kind of discussion related to Hanami. Feel free to ask a question, share your project with others, ask for guidance and best practices, offer your help contributing to a project, or anything else.
+discourse.hanamirb.org
+
-We have an official chat room on Gitter. If you need a quick question answered, this is the best place to do it. Also, if you are working on a project and you need any kind of advice, please feel free to ask. Someone will be there to answer most of the times. We are always happy to help.
-hanami/chat
+We have an official chat room on Discourse, too. If you need a quick question answered, this is a great place for it. We are always happy to help. You need to create an account there in order to read or chat, but you can authenticate with GitHub so it's quite simple.
+Hanami Discourse Chat
On the official Hanami blog, you can find the detailed announcements for new releases, some interesting use cases and things the team writes around the code they usually write.
Hanami Blog
-
-The Hanami forum is a good place for general discussions. Feel free to ask a question, share your project with others, ask for guidance and best practices, offer your help contributing to a project, or anything else.
-discourse.hanamirb.org
-
We regularly tweet general announcements on releases and events where Hanami is represented in any way. We also retweet interesting tweets from the Hanami and Ruby community. Please mention @hanamirb
or use #hanamirb
if you are tweeting about Hanami.
@hanamirb , #hanamirb
-
-On our reddit page, we link blog posts about new releases, have links to useful Hanami learning material, and have interesting discussions with the Hanami community.
-r/hanamirb
-
-
-If you have any questions about Hanami, you can always ask on StackOverflow. Make sure you use the Hanami tag. You can also always help others solving their problems. You will make others happy, as you are when you get help.
-hanami tag
-
-
-The awesome-hanami Github repository lists Hanami gems, libraries and projects that use Hanami. Also, there are some useful links to know more about Hanami and its users.
-awesome-hanami.org
+
+Hanami Mastery initiative is a collection of articles and video tutorials about Hanami and its dependencies, as well as all awesome gems that can be used within Hanami framework.
+hanamimastery.com , Content Tagged with Hanami
To stay updated with the latest releases, to receive code examples, implementation details and announcements, please consider to subscribe to the Hanami mailing list .
+
+Hanami 2
+
+
+
+Hanami 1
+
+
-
-Find and join a local Hanami user group and spread the word about Hanami. Share experiences and help others to get started! If you consider starting a new local user group, feel free to get in touch with us and we can help you with the setup.
-
-
Help is welcome and much appreciated, whether you are an experienced developer or just looking for sending your first pull request. Please check the open tikets. Be sure to follow the Contributor Code of Conduct below.
Open Tickets
+<%# BEGIN CODE OF CONDUCT %>
+
-
-
-
-Our Pledge
-
-In the interest of fostering an open and welcoming environment, we as
-contributors and maintainers pledge to making participation in our project and
-our community a harassment-free experience for everyone, regardless of age, body
-size, disability, ethnicity, gender identity and expression, level of experience,
-nationality, personal appearance, race, religion, or sexual identity and
-orientation.
-
-Our Standards
-
-Examples of behavior that contribute to creating a positive environment
-include:
+Our Pledge
+ We as members, contributors, and leaders pledge to make participation in our community a harassment-free experience for everyone, regardless of age, body size, visible or invisible disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education, socio-economic status, nationality, personal appearance, race, caste, color, religion, or sexual identity and orientation.
+We pledge to act and interact in ways that contribute to an open, welcoming, diverse, inclusive, and healthy community.
+Our Standards
+ Examples of behavior that contributes to a positive environment for our community include:
- Using welcoming and inclusive language
- Being respectful of differing viewpoints and experiences
- Gracefully accepting constructive criticism
- Focusing on what is best for the community
- Showing empathy towards other community members
+ Demonstrating empathy and kindness toward other people
+ Being respectful of differing opinions, viewpoints, and experiences
+ Giving and gracefully accepting constructive feedback
+ Accepting responsibility and apologizing to those affected by our mistakes,
+ and learning from the experience
+ Focusing on what is best not just for us as individuals, but for the overall
+ community
-
-Examples of unacceptable behavior by participants include:
-
+Examples of unacceptable behavior include:
- The use of sexualized language or imagery and unwelcome sexual attention or advances
- Trolling, insulting/derogatory comments, and personal or political attacks
+ The use of sexualized language or imagery, and sexual attention or advances of
+ any kind
+ Trolling, insulting or derogatory comments, and personal or political attacks
Public or private harassment
- Publishing others' private information, such as a physical or electronic address, without explicit permission
- Other conduct which could reasonably be considered inappropriate in a professional setting
+ Publishing othersβ private information, such as a physical or email address,
+ without their explicit permission
+ Other conduct which could reasonably be considered inappropriate in a
+ professional setting
-Our Responsibilities
-
-Project maintainers are responsible for clarifying the standards of acceptable
-behavior and are expected to take appropriate and fair corrective action in
-response to any instances of unacceptable behavior.
-
-Project maintainers have the right and responsibility to remove, edit, or
-reject comments, commits, code, wiki edits, issues, and other contributions
-that are not aligned to this Code of Conduct, or to ban temporarily or
-permanently any contributor for other behaviors that they deem inappropriate,
-threatening, offensive, or harmful.
-
-Scope
-
-This Code of Conduct applies both within project spaces and in public spaces
-when an individual is representing the project or its community. Examples of
-representing a project or community include using an official project e-mail
-address, posting via an official social media account, or acting as an appointed
-representative at an online or offline event. Representation of a project may be
-further defined and clarified by project maintainers.
-
-Enforcement
-
-Instances of abusive, harassing, or otherwise unacceptable behavior may be
-reported by contacting the project team at admin@hanamirb.org. All
-complaints will be reviewed and investigated and will result in a response that
-is deemed necessary and appropriate to the circumstances. The project team is
-obligated to maintain confidentiality with regard to the reporter of an incident.
-Further details of specific enforcement policies may be posted separately.
-
-Project maintainers who do not follow or enforce the Code of Conduct in good
-faith may face temporary or permanent repercussions as determined by other
-members of the project's leadership.
-
-Attribution
-
-This Code of Conduct is adapted from the Contributor Covenant , version 1.4,
-available at http://contributor-covenant.org/version/1/4 .
+Enforcement Responsibilities
+ Community leaders are responsible for clarifying and enforcing our standards of acceptable behavior and will take appropriate and fair corrective action in response to any behavior that they deem inappropriate, threatening, offensive, or harmful.
+Community leaders have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, and will communicate reasons for moderation decisions when appropriate.
+
+Scope
+ This Code of Conduct applies within all community spaces, and also applies when an individual is officially representing the community in public spaces. Examples of representing our community include using an official e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event.
+
+Enforcement
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be reported to the community leaders responsible for enforcement at admin@hanamirb.org. All complaints will be reviewed and investigated promptly and fairly.
+All community leaders are obligated to respect the privacy and security of the reporter of any incident.
+
+Enforcement Guidelines
+ Community leaders will follow these Community Impact Guidelines in determining the consequences for any action they deem in violation of this Code of Conduct:
+1. Correction
+ Community Impact : Use of inappropriate language or other behavior deemed unprofessional or unwelcome in the community.
+Consequence : A private, written warning from community leaders, providing clarity around the nature of the violation and an explanation of why the behavior was inappropriate. A public apology may be requested.
+2. Warning
+ Community Impact : A violation through a single incident or series of actions.
+Consequence : A warning with consequences for continued behavior. No interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, for a specified period of time. This includes avoiding interactions in community spaces as well as external channels like social media. Violating these terms may lead to a temporary or permanent ban.
+3. Temporary Ban
+ Community Impact : A serious violation of community standards, including sustained inappropriate behavior.
+Consequence : A temporary ban from any sort of interaction or public communication with the community for a specified period of time. No public or private interaction with the people involved, including unsolicited interaction with those enforcing the Code of Conduct, is allowed during this period. Violating these terms may lead to a permanent ban.
+4. Permanent Ban
+ Community Impact : Demonstrating a pattern of violation of community standards, including sustained inappropriate behavior, harassment of an individual, or aggression toward or disparagement of classes of individuals.
+Consequence : A permanent ban from any sort of public interaction within the community.
+
+Attribution
+ This Code of Conduct is adapted from the Contributor Covenant , version 2.1 .
+<%# END CODE OF CONDUCT %>
The Hanami logo is Β© Luca Guidi, but you can download and use it for non-commercial purposes.
diff --git a/source/donate.html.erb b/source/donate.html.erb
deleted file mode 100644
index af24e4693..000000000
--- a/source/donate.html.erb
+++ /dev/null
@@ -1,26 +0,0 @@
----
-title: Donate
----
-
-
-Hanami is made by an inclusive Community .Please help us to stay independent: consider to donate .
-
-Backers
-A huge THANK YOU <3 to our supporters!
-
-
diff --git a/source/donate.html.md b/source/donate.html.md
new file mode 100644
index 000000000..e6aa3f86e
--- /dev/null
+++ b/source/donate.html.md
@@ -0,0 +1,48 @@
+---
+title: GitHub Sponsors
+---
+
+
+
+You can become a [Hanami sponsor on GitHub](https://github.com/sponsors/hanami) in order to keep the project independent and help with sustainable development.
+
+## Sponsorship
+
+Hanami is a big and ambitious Open Source project which is being developed by a handful of expert Rubyists. The project unifies an entire ecosystem of Open Source libraries and tools that you can find in other organizations like [dry-rb](https://dry-rb.org) or [rom-rb](https://rom-rb.org).
+
+Hanami aims to take application development using Ruby to the next level. Whether you're building a web or a non-web application - you **can benefit from Hanami** and its powerful features.
+
+This is a big effort that has already consumed thousands of hours of hard work. In order to be able to ship Hanami 2.0 faster and then to be able to keep working on Hanami and related projects from its ecosystem, we're seeking sponsorship.
+
+Having financial support enables us to cover ongoing expenses and devote much more _dedicated time_ to Open Source work. This can speed up development efforts significantly as well as increase the quality of the work.
+
+By supporting Hanami, you can be sure that the funds will go directly to people involved with the project in order to let them work on the project in a sustainable way. The funds may also be used to cover various ongoing expenses like infrastructure, domains, hosting etc.
+
+Please note that this sponsorship is based on mutual trust and does not establish any legal obligations. If you decide to sponsor Hanami, you simply trust that we β the developers working on the project β are going to continue doing our best work in order to finish Hanami 2.0 and continue working on it in the future.
+
+We appreciate your support!
+
+[Become a Sponsor](https://github.com/sponsors/hanami)!
+
+
+
+A huge THANK YOU <3 to our supporters!
+
+
diff --git a/source/guides.html.erb b/source/guides.html.erb
new file mode 100644
index 000000000..cde30c5af
--- /dev/null
+++ b/source/guides.html.erb
@@ -0,0 +1,15 @@
+---
+title: Guides
+---
+
+
+Hanami Guides are now available at https://guides.hanamirb.org .
+You'll be redirected in 5 seconds to the new location.
+
+
diff --git a/source/guides/1.0/actions/basic-usage.md b/source/guides/1.0/actions/basic-usage.md
deleted file mode 100644
index 8dc8bde47..000000000
--- a/source/guides/1.0/actions/basic-usage.md
+++ /dev/null
@@ -1,134 +0,0 @@
----
-title: Guides - Actions Basic Usage
-version: 1.0
----
-
-# Basic Usage
-
-## Requests Handling
-
-In the [previous section](/guides/1.0/actions/overview), we generated an action. Now let's use it.
-
-First, we check our routes:
-
-```ruby
-# apps/web/config/routes.rb
-get '/dashboard', to: 'dashboard#index'
-```
-
-### View Rendering
-
-Then we edit the corresponding template:
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-Dashboard
-```
-
-Here is how Hanami handles an incoming request:
-
- 1. The router creates a new instance of `Web::Controllers::Dashboard::Index` and invokes `#call`.
- 2. The application creates a new instance of `Web::Views::Dashboard::Index` and invokes `#render`.
- 3. The application returns the response to the browser.
-
-
- For a given action named Web::Controllers::Dashboard::Index
, a corresponding view MUST be present: Web::Views::Dashboard::Index
.
-
-
-If we visit `/dashboard` we should see `Dashboard ` in our browser.
-
-### Bypass Rendering
-
-By default an action takes care of the HTTP status code and response header, but not of the body of the response.
-As seen above, it delegates the corresponding view to render and set this value.
-
-Sometimes we want to bypass this process.
-For instance we want to return a simple body like `OK`.
-To involve a view in this case is a waste of CPU cycles.
-
-If we set the body of the response from an action, **our application will ignore the view**.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- self.body = 'OK'
- end
- end
-end
-```
-
-Here is how Hanami handles an incoming request in this case:
-
- 1. The router creates a new instance of `Web::Controllers::Dashboard::Index` and invokes `#call`.
- 2. The application detects that a body is already set and doesn't instantiate the view.
- 3. The application returns the response to the browser.
-
-If we visit `/dashboard` again, now we should see `OK`.
-
-
- If the response body was already set by an action, the rendering process is bypassed.
-
-
-With direct body assignment, **we can safely delete the corresponding view and template**.
-
-## Initialization
-
-Actions are instantiated for us by Hanami at the runtime: for each incoming request, we'll automatically get a new instance.
-Because actions are objects, **we can take control on their initialization** and eventually [_inject_ our dependencies](http://en.wikipedia.org/wiki/Dependency_injection).
-This is a really useful technique for unit testing our actions.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def initialize(greeting: Greeting.new)
- @greeting = greeting
- end
-
- def call(params)
- self.body = @greeting.message
- end
- end
-end
-```
-
-There is a limitation that we should always be kept in mind:
-
-
- Action initializer MUST have an arity of 0.
-
-
-The following initializers are valid:
-
-```ruby
-# no arguments
-def initialize
- # ...
-end
-
-# default arguments
-def initialize(greeting = Greeting.new)
- # ...
-end
-
-# keyword arguments
-def initialize(greeting: Greeting.new)
- # ...
-end
-
-# options
-def initialize(options = {})
- # ...
-end
-
-# splat arguments
-def initialize(*args)
- # ...
-end
-```
diff --git a/source/guides/1.0/actions/control-flow.md b/source/guides/1.0/actions/control-flow.md
deleted file mode 100644
index d4bb1dfa7..000000000
--- a/source/guides/1.0/actions/control-flow.md
+++ /dev/null
@@ -1,262 +0,0 @@
----
-title: Guides - Action Control Flow
-version: 1.0
----
-
-# Control Flow
-
-## Callbacks
-
-If we want to execute some logic before and/or after `#call` is executed, we can use a callback.
-Callbacks are useful to declutter code for common tasks like checking if a user is signed in, set a record, handle 404 responses or tidy up the response.
-
-The corresponding DSL methods are `before` and `after`.
-These methods each accept a symbol that is the name of the method that we want to call, or an anonymous proc.
-
-### Methods
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before :track_remote_ip
-
- def call(params)
- # ...
- end
-
- private
- def track_remote_ip
- @remote_ip = request.ip
- # ...
- end
- end
-end
-```
-
-With the code above, we are tracking the remote IP address for analytics purposes.
-Because it isn't strictly related to our business logic, we move it to a callback.
-
-A callback method can optionally accept an argument: `params`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before :validate_params
-
- def call(params)
- # ...
- end
-
- private
- def validate_params(params)
- # ...
- end
- end
-end
-```
-
-### Proc
-
-The examples above can be rewritten with anonymous procs.
-They are bound to the instance context of the action.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before { @remote_ip = request.ip }
-
- def call(params)
- # @remote_ip is available here
- # ...
- end
- end
-end
-```
-
-A callback proc can bound an optional argument: `params`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before {|params| params.valid? }
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-
-Don't use callbacks for model domain logic operations like sending emails.
-This is an antipattern that causes a lot of problems for code maintenance, testability and accidental side effects.
-
-
-## Halt
-
-Using exceptions for control flow is expensive for the Ruby VM.
-There is a lightweight alternative that our language supports: **signals** (see `throw` and `catch`).
-
-Hanami takes advantage of this mechanism to provide **faster control flow** in our actions via `#halt`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- halt 401 unless authenticated?
- # ...
- end
-
- private
- def authenticated?
- # ...
- end
- end
-end
-```
-
-When used, this API **interrupts the flow**, and returns the control to the framework.
-Subsequent instructions will be entirely skipped.
-
-
-When halt
is used, the flow is interrupted and the control is passed back to the framework.
-
-
-That means that `halt` can be used to skip `#call` invocation entirely if we use it in a `before` callback.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before :authenticate!
-
- def call(params)
- # ...
- end
-
- private
- def authenticate!
- halt 401 if current_user.nil?
- end
- end
-end
-```
-
-`#halt` accepts an HTTP status code as the first argument.
-When used like this, the body of the response will be set with the corresponding message (eg. "Unauthorized" for `401`).
-
-An optional second argument can be passed to set a custom body.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- halt 404, "These aren't the droids you're looking for"
- end
- end
-end
-```
-
-When `#halt` is used, **Hanami** renders a default status page with the HTTP status and the message.
-
-
-
-To customize the UI for the HTTP 404 error, you can use a [custom error page](/guides/1.0/views/custom-error-pages).
-
-## HTTP Status
-
-In case you want let the view to handle the error, instead of using `#halt`, you should use `#status=`.
-
-The typical case is a **failed form submission**: we want to return a non-successful HTTP status (`422`) and let the view to render the form again and show the validation errors.
-
-```ruby
-# apps/web/controllers/books/create.rb
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- params do
- required(:title).filled(:str?)
- end
-
- def call(params)
- if params.valid?
- # persist
- else
- self.status = 422
- end
- end
- end
-end
-```
-
-```ruby
-# apps/web/views/books/create.rb
-module Web::Views::Books
- class Create
- include Web::View
- template 'books/new'
- end
-end
-```
-
-```erb
-# apps/web/templates/books/new.html.erb
-<% unless params.valid? %>
-
- <% params.error_messages.each do |error| %>
- <%= error %>
- <% end %>
-
-<% end %>
-
-
-```
-
-## Redirect
-
-A special case of control flow management is relative to HTTP redirect.
-If we want to reroute a request to another resource we can use `redirect_to`.
-
-When `redirect_to` is invoked, control flow is stopped and **subsequent code in the action is not executed**.
-
-It accepts a string that represents an URI, and an optional `:status` argument.
-By default the status is set to `302`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- redirect_to routes.root_path
- foo('bar') # This line will never be executed
- end
- end
-end
-```
-
-### Back
-
-Sometimes you'll want to `redirect_to` back in your browser's history so the easy way to do it
-is the following way:
-
-```ruby
-redirect_to request.get_header("Referer") || fallback_url
-```
diff --git a/source/guides/1.0/actions/cookies.md b/source/guides/1.0/actions/cookies.md
deleted file mode 100644
index 3074a332e..000000000
--- a/source/guides/1.0/actions/cookies.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: Guides - Action Cookies
-version: 1.0
----
-
-# Cookies
-
-## Enable Cookies
-
-Hanami applies _"batteries included, but not installed"_ philosophy.
-Cookies are a feature that is present but needs to be activated.
-
-In our application settings there is a line to uncomment.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- cookies true
- end
- end
-end
-```
-
-From now on, cookies are automatically sent for each response.
-
-### Settings
-
-With that configuration we can specify options that will be set for all cookies we send from our application.
-
- * `:domain` - `String` (`nil` by default), the domain
- * `:path` - `String` (`nil` by default), a relative URL
- * `:max_age` - `Integer` (`nil` by default), cookie duration expressed in seconds
- * `:secure` - `Boolean` (`true` by default if using SSL), restrict cookies to secure connections
- * `:httponly` - `Boolean` (`true` by default), restrict JavaScript access to cookies
-
-## Usage
-
-Cookies behave like a Hash: we can read, assign and remove values.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- cookies[:b] # read
- cookies[:a] = 'foo' # assign
- cookies[:c] = nil # remove
- cookies[:d] = { value: 'foo', path: '/bar' } # assign with options
- end
- end
-end
-```
-
-When setting a value, a cookie can accept a `String` or a `Hash` to specify inline options.
-General settings are applied automatically but these options can be used to override values case by case.
-
-### Example
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- cookies max_age: 300 # 5 minutes
- end
- end
-end
-```
-
-We're going to set two cookies from the action: the first will inherit application configuration, while the second overrides the default value.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- # Set-Cookie:a=foo; max-age=300; HttpOnly
- cookies[:a] = 'foo'
-
- # Set-Cookie:b=bar; max-age=100; HttpOnly
- cookies[:b] = { value: 'bar', max_age: 100 }
- end
- end
-end
-```
diff --git a/source/guides/1.0/actions/exception-handling.md b/source/guides/1.0/actions/exception-handling.md
deleted file mode 100644
index 847b37c19..000000000
--- a/source/guides/1.0/actions/exception-handling.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: Guides - Action Exception Handling
-version: 1.0
----
-
-# Exception Handling
-
-Actions have an elegant API for exception handling.
-The behavior changes according to the current Hanami environment and the custom settings in our configuration.
-
-## Default Behavior
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- raise 'boom'
- end
- end
-end
-```
-
-Exceptions are automatically caught when in production mode, but not in development.
-In production, for our example, the application returns a `500` (Internal Server Error); in development, we'll see the stack trace and all the information to debug the code.
-
-This behavior can be changed with the `handle_exceptions` setting in `apps/web/application.rb`.
-
-## Custom HTTP Status
-
-If we want to map an exception to a specific HTTP status code, we can use `handle_exception` DSL.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- handle_exception ArgumentError => 400
-
- def call(params)
- raise ArgumentError
- end
- end
-end
-```
-
-`handle_exception` accepts a Hash where the key is the exception to handle, and the value is the corresponding HTTP status code.
-In our example, when `ArgumentError` is raised, it will be handled as a `400` (Bad Request).
-
-## Custom Handlers
-
-If the mapping with a custom HTTP status doesn't fit our needs, we can specify a custom handler and manage the exception by ourselves.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class PermissionDenied < StandardError
- def initialize(role)
- super "You must be admin, but you are: #{ role }"
- end
- end
-
- class Index
- include Web::Action
- handle_exception PermissionDenied => :handle_permission_error
-
- def call(params)
- unless current_user.admin?
- raise PermissionDenied.new(current_user.role)
- end
-
- # ...
- end
-
- private
- def handle_permission_error(exception)
- status 403, exception.message
- end
- end
-end
-```
-
-If we specify the name of a method (as a symbol) as the value for `handle_exception`, this method will be used to respond to the exception.
-In the example above we want to protect the action from unwanted access: only admins are allowed.
-
-When a `PermissionDenied` exception is raised it will be handled by `:handle_permission_error`.
-It MUST accept an `exception` argument—the exception instance raised inside `#call`.
-
-
-When specifying a custom exception handler, it MUST accept an exception
argument.
-
diff --git a/source/guides/1.0/actions/exposures.md b/source/guides/1.0/actions/exposures.md
deleted file mode 100644
index 410c5b231..000000000
--- a/source/guides/1.0/actions/exposures.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: Guides - Action Exposures
-version: 1.0
----
-
-# Exposures
-
-For complex use cases we may want to pass data to views in order to present it to our users.
-Hanami puts emphasis on explicitness: data isn't shared between the controller action and the view unless we tell it to do so.
-
-We use a simple and powerful mechanism to achieve our goal: _**exposures**_.
-Exposures create a _getter_ on the action for the given name(s) and only the whitelisted instance variables are made available to the corresponding view.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- expose :greeting
-
- def call(params)
- @greeting = "Hello"
- @foo = 23
- end
- end
-end
-```
-
-In the example above we have exposed `:greeting`, but not `:foo`.
-Only `greeting` can be used from the view and template.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
-
- def welcome_message
- greeting + " and welcome"
- end
- end
-end
-```
-
-If we try to use `foo`, Ruby will raise a `NoMethodError`.
diff --git a/source/guides/1.0/actions/http-caching.md b/source/guides/1.0/actions/http-caching.md
deleted file mode 100644
index 58791c6e7..000000000
--- a/source/guides/1.0/actions/http-caching.md
+++ /dev/null
@@ -1,140 +0,0 @@
----
-title: Guides - Action HTTP Caching
-version: 1.0
----
-
-# HTTP Caching
-
-We refer to HTTP caching as the set of techniques for HTTP 1.1 and implemented by browser vendors in order to make faster interactions with the server.
-There are a few headers that, if sent, will enable these HTTP caching mechanisms.
-
-## Cache Control
-
-Actions offer a DSL to set a special header `Cache-Control`.
-The first argument is a cache response directive like `:public` or `"must-revalidate"`, while the second argument is a set of options like `:max_age`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- include Hanami::Action::Cache
-
- cache_control :public, max_age: 600
- # => Cache-Control: public, max-age: 600
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-## Expires
-
-Another HTTP caching special header is `Expires`.
-It can be used for retrocompatibility with old browsers which don't understand `Cache-Control`.
-
-Hanami's solution for _expire_ combines support for all the browsers by sending both the headers.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- include Hanami::Action::Cache
- expires 60, :public, max_age: 300
- # => Expires: Mon, 18 May 2015 09:19:18 GMT
- # Cache-Control: public, max-age: 300
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-## Conditional GET
-
-_Conditional GET_ is a two step workflow to inform browsers that a resource hasn't changed since the last visit.
-At the end of the first request, the response includes special HTTP response headers that the browser will use next time it comes back.
-If the header matches the value that the server calculates, then the resource is still cached and a `304` status (Not Modified) is returned.
-
-### ETag
-
-The first way to match a resource freshness is to use an identifier (usually an MD5 token).
-Let's specify it with `fresh etag:`.
-
-If the given identifier does NOT match the `If-None-Match` request header, the request will return a `200` with an `ETag` response header with that value.
-If the header does match, the action will be halted and a `304` will be returned.
-
-```ruby
-# apps/web/controllers/users/show.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Users
- class Show
- include Web::Action
- include Hanami::Action::Cache
-
- def call(params)
- @user = UserRepository.new.find(params[:id])
- fresh etag: etag
-
- # ...
- end
-
- private
-
- def etag
- "#{ @user.id }-#{ @user.updated_at }"
- end
- end
-end
-
-# Case 1 (missing or non-matching If-None-Match)
-# GET /users/23
-# => 200, ETag: 84e037c89f8d55442366c4492baddeae
-
-# Case 2 (matching If-None-Match)
-# GET /users/23, If-None-Match: 84e037c89f8d55442366c4492baddeae
-# => 304
-```
-
-### Last Modified
-
-The second way is to use a timestamp via `fresh last_modified:`.
-
-If the given timestamp does NOT match `If-Modified-Since` request header, it will return a `200` and set the `Last-Modified` response header with the timestamp value.
-If the timestamp does match, the action will be halted and a `304` will be returned.
-
-```ruby
-# apps/web/controllers/users/show.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Users
- class Show
- include Web::Action
- include Hanami::Action::Cache
-
- def call(params)
- @user = UserRepository.new.find(params[:id])
- fresh last_modified: @user.updated_at
-
- # ...
- end
- end
-end
-
-# Case 1 (missing or non-matching Last-Modified)
-# GET /users/23
-# => 200, Last-Modified: Mon, 18 May 2015 10:04:30 GMT
-
-# Case 2 (matching Last-Modified)
-# GET /users/23, If-Modified-Since: Mon, 18 May 2015 10:04:30 GMT
-# => 304
-```
diff --git a/source/guides/1.0/actions/mime-types.md b/source/guides/1.0/actions/mime-types.md
deleted file mode 100644
index d7c197375..000000000
--- a/source/guides/1.0/actions/mime-types.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: Guides - Action MIME Types
-version: 1.0
----
-
-# MIME Types
-
-Actions have advanced features for MIME type detection, automatic headers, whitelisting etc..
-
-## Request Introspection
-
-In order to understand what the requested MIME type is, an action looks at the `Accept` request header and exposes a high level API: `#format` and `#accept?`.
-
-The first returns a symbol representation of the MIME type (eg. `:html`, `:json`, `:xml` etc..), while the second is a query method that accepts a MIME type string and checks if it's accepted by the current browser.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- puts format # => :html
-
- puts accept?('text/html') # => true
- puts accept?('application/png') # => false
- end
- end
-end
-```
-
-## Automatic Content-Type
-
-An action returns the `Content-Type` response header automatically according to the requested MIME Type and charset.
-
-If the client asks for `Accept: text/html,application/xhtml+xml,application/xml;q=0.9`, the action will return `Content-Type: text/html; charset=utf-8`.
-
-### Default Request Format
-
-If a client asks for a generic `Accept: */*`, the action will fall back to the **application default format**.
-This is a setting that allows us to safely handle cases like our example; the default value is `:html`.
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- default_request_format :json
- end
- end
-end
-```
-
-### Default Response Format
-
-If we are building a JSON API app, it can be useful to specify a `:json` as default MIME Type for the response.
-The default value is `:html`.
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- default_response_format :json
- end
- end
-end
-```
-
-### Default Charset
-
-Similarly, we can specify a different default charset to return.
-The standard value is `utf-8`, but we can change it in our settings.
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- default_charset 'koi8-r'
- end
- end
-end
-```
-
-### Override
-
-There is a way we can force the returned `Content-Type`: use `#format=`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- puts self.format # => :html
-
- # force a different value
- self.format = :json
- puts self.format # => :json
- end
- end
-end
-```
-
-The example above will return `Content-Type: application/json; charset=utf-8`.
-
-## Whitelisting
-
-We can also restrict the range of accepted MIME Types.
-If the incoming request doesn't satisfy this constraint, the application will return a `Not Acceptable` status (`406`).
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- accept :html, :json
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-## Register MIME Types
-
-Hanami knows about more than 100 of the most common MIME types.
-However, we may want to add custom types in order to use them with `#format=` or `.accept`.
-
-In our application settings we can use `controller.format`, which accepts a Hash where the key is the format symbol (`:custom`) and the value is a string expressed in the MIME type standard (`application/custom`).
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- controller.format custom: 'application/custom'
- end
- end
-end
-```
diff --git a/source/guides/1.0/actions/overview.md b/source/guides/1.0/actions/overview.md
deleted file mode 100644
index 677e2ad1e..000000000
--- a/source/guides/1.0/actions/overview.md
+++ /dev/null
@@ -1,88 +0,0 @@
----
-title: Guides - Actions Overview
-version: 1.0
----
-
-# Overview
-
-An action is an endpoint that handles incoming HTTP requests for a specific [route](/guides/1.0/routing/overview).
-In a Hanami application, an **action is an object**, while a **controller is a Ruby module** that groups them.
-
-This design provides self contained actions that don't share their context accidentally with other actions. It also prevents gigantic controllers.
-It has several advantages in terms of testability and control of an action.
-
-## A Simple Action
-
-Hanami ships with a generator for actions. Let's create a new one:
-
-```shell
-hanami generate action web dashboard#index
-```
-
-Let's examine the action:
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- end
- end
-end
-```
-
-### Naming
-
-That file begins with a module declaration.
-
-The first token is the name of our application: `Web`.
-Hanami can run multiple applications within the same Ruby process.
-They are located under `apps/`.
-Their name is used as a **top-level module to contain inner components** like actions and views, in order to **avoid naming collisions**.
-If we have another action `Home::Index` under an application `Admin`, the two of them can coexist inside the same codebase.
-
-The second token is a conventional name: `Controllers`.
-**All the controllers are nested under it.**
-This module is generated at runtime for us, when the application starts.
-
-
- For a given application named Web
, controllers are available under Web::Controllers
.
-
-
-The last bit is `Dashboard`, which is our controller.
-
-The whole action name is `Web::Controllers::Dashboard::Index`.
-
-
- You should avoid giving your action modules the same name as your application, e.g. avoid naming a controller Web
in an app named Web
. If you have a controller name like Web::Controllers::Web
then some code across your app will break with errors about constants not being found, for example in views which include Web::Layout
. This is because Ruby starts constant lookup with the current module, so a constant like Web::Layout
referenced by code in the Web::Controllers::Web
or Web::Controllers::Web::MyAction
module will be converted to Web::Controllers::Web::Layout
, which can't be found and causes a constant lookup error.
-
-
- If you absolutely must name a controller with the same name as your application, you'll need to explicitly set the namespace lookup for things which should be included from immediately under the app, not the controller by prefixing those names with ::
, e.g. change your views to include ::Web::Layout
instead of include Web::Layout
, and using include ::Web::Action
in your controllers.
-
-
-###Β Action Module
-
-Hanami philosophy emphasizes _composition over inheritance_ and avoids the [framework superclass antipattern](http://michaelfeathers.typepad.com/michael_feathers_blog/2013/01/the-framework-superclass-anti-pattern.html).
-For this reason, all the components are provided as **modules to include** instead of base classes to inherit from.
-
-Like we said before, Hanami can run multiple apps within the same Ruby process.
-Each of them has its own configuration.
-To keep separated actions from an application named `Web` and an application named `Admin`, we include `Web::Action` and `Admin::Action` respectively.
-
-In our example, we have a directive `include Web::Action`.
-That means our action will behave according to the configuration of the `Web` application.
-
-
- For a given application named Web
, the action mixin to include is Web::Action
.
-
-
-### Interface
-
-When we include `Web::Action`, we made our object compliant with [Hanami::Controller](https://github.com/hanami/controller)'s actions.
-We need to implement `#call`, which is a method that accepts only one argument: `params`.
-That is the object that carries the payload that comes from incoming HTTP requests from the [router](/guides/1.0/routing/basic-usage).
-
-This interface reminds us of Rack.
-Indeed, our action is compatible with the Rack protocol.
diff --git a/source/guides/1.0/actions/parameters.md b/source/guides/1.0/actions/parameters.md
deleted file mode 100644
index 9d8869222..000000000
--- a/source/guides/1.0/actions/parameters.md
+++ /dev/null
@@ -1,301 +0,0 @@
----
-title: Guides - Action Parameters
-version: 1.0
----
-
-# Parameters
-
-Parameters are taken from the Rack env and passed as an argument to `#call`.
-They are similar to a Ruby Hash, but they offer an expanded set of features.
-
-## Sources
-
-Params can come from:
-
- * [Router variables](/guides/1.0/routing/basic-usage) (eg. `/books/:id`)
- * Query string (eg. `/books?title=Hanami`)
- * Request body (eg. a `POST` request to `/books`)
-
-## Access
-
-To access the value of a param, we can use the _subscriber operator_ `#[]`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- self.body = "Query string: #{ params[:q] }"
- end
- end
-end
-```
-
-If we visit `/dashboard?q=foo`, we should see `Query string: foo`.
-
-### Symbol Access
-
-Params and nested params can be referenced **only** via symbols.
-
-```ruby
-params[:q]
-params[:book][:title]
-```
-
-Now, what happens if the parameter `:book` is missing from the request?
-Because `params[:book]` is `nil`, we can't access `:title`.
-In this case Ruby will raise a `NoMethodError`.
-
-We have a safe solution for our problem: `#get`.
-It accepts a list of symbols, where each symbol represents a level in our nested structure.
-
-```ruby
-params.get(:book, :title) # => "Hanami"
-params.get(:unknown, :nested, :param) # => nil instead of NoMethodError
-```
-
-## Whitelisting
-
-In order to show how whitelisting works, let's create a new action:
-
-```shell
-bundle exec hanami generate action web signup#create
-```
-
-We want to provide self-registration for our users.
-We build a HTML form which posts to an action that accepts the payload and stores it in the `users` table.
-That table has a boolean column `admin` to indicate whether a person has administration permissions.
-
-A malicious user can exploit this scenario by sending this extra parameter to our application, thereby making themselves an administrator.
-
-We can easily fix this problem by filtering the allowed parameters that are permitted inside our application.
-Please always remember that **params represent untrusted input**.
-
-We use `.params` to map the structure of the (nested) parameters.
-
-```ruby
-# apps/web/controllers/signup/create.rb
-module Web::Controllers::Signup
- class Create
- include Web::Action
-
- params do
- required(:email).filled
- required(:password).filled
-
- required(:address).schema do
- required(:country).filled
- end
- end
-
- def call(params)
- puts params[:email] # => "alice@example.org"
- puts params[:password] # => "secret"
- puts params[:address][:country] # => "Italy"
-
- puts params[:admin] # => nil
- end
- end
-end
-```
-
-Even if `admin` is sent inside the body of the request, it isn't accessible from `params`.
-
-## Validations & Coercion
-
-### Use Cases
-
-In our example (called _"Signup"_), we want to make `password` a required param.
-
-Imagine we introduce a second feature: _"Invitations"_.
-An existing user can ask someone to join.
-Because the invitee will decide a password later on, we want to persist that `User` record without that value.
-
-If we put `password` validation in `User`, we need to handle these two use cases with a conditional.
-But in the long term this approach is painful from a maintenance perspective.
-
-```ruby
-# Example of poor style for validations
-class User
- attribute :password, presence: { if: :password_required? }
-
- private
- def password_required?
- !invited_user? && !admin_password_reset?
- end
-end
-```
-
-We can see validations as the set of rules for data correctness that we want for **a specific use case**.
-For us, a `User` can be persisted with or without a password, **depending on the workflow** and the route through
-which the `User` is persisted.
-
-### Boundaries
-
-The second important aspect is that we use validations to prevent invalid inputs to propagate in our system.
-In an MVC architecture, the model layer is the **farthest** from the input.
-It's expensive to check the data right before we create a record in the database.
-
-If we **consider correct data as a precondition** before starting our workflow, we should stop unacceptable inputs as soon as possible.
-
-Think of the following method.
-We don't want to continue if the data is invalid.
-
-```ruby
-def expensive_computation(argument)
- return if argument.nil?
- # ...
-end
-```
-
-### Usage
-
-We can coerce the Ruby type, validate if a param is required, determine if it is within a range of values, etc..
-
-```ruby
-# apps/web/controllers/signup/create.rb
-module Web::Controllers::Signup
- class Create
- include Web::Action
- MEGABYTE = 1024 ** 2
-
- params do
- required(:name).filled(:str?)
- required(:email).filled(:str?, format?: /@/).confirmation
- required(:password).filled(:str?).confirmation
- required(:terms_of_service).filled(:bool?)
- required(:age).filled(:int?, included_in?: 18..99)
- optional(:avatar).filled(size?: 1..(MEGABYTE * 3))
- end
-
- def call(params)
- if params.valid?
- # ...
- else
- # ...
- end
- end
- end
-end
-```
-
-Parameter validations are delegated, under the hood, to [Hanami::Validations](https://github.com/hanami/validations).
-Please check the related documentation for a complete list of options and how to share code between validations.
-
-## Concrete Classes
-
-The params DSL is really quick and intuitive but it has the drawback that it can be visually noisy and makes it hard to unit test.
-An alternative is to extract a class and pass it as an argument to `.params`.
-
-```ruby
-# apps/web/controllers/signup/my_params.rb
-module Web::Controllers::Signup
- class MyParams < Web::Action::Params
- MEGABYTE = 1024 ** 2
-
- params do
- required(:name).filled(:str?)
- required(:email).filled(:str?, format?: /@/).confirmation
- required(:password).filled(:str?).confirmation
- required(:terms_of_service).filled(:bool?)
- required(:age).filled(:int?, included_in?: 18..99)
- optional(:avatar).filled(size?: 1..(MEGABYTE * 3)
- end
- end
-end
-```
-
-```ruby
-# apps/web/controllers/signup/create.rb
-require_relative './my_params'
-
-module Web::Controllers::Signup
- class Create
- include Web::Action
- params MyParams
-
- def call(params)
- if params.valid?
- # ...
- else
- # ...
- end
- end
- end
-end
-```
-
-## Body Parsers
-
-Rack ignores request bodies unless they come from a form submission.
-If we have a JSON endpoint, the payload isn't available in `params`.
-
-```ruby
-module Web::Controllers::Books
- class Create
- include Web::Action
- accept :json
-
- def call(params)
- puts params.to_h # => {}
- end
- end
-end
-```
-
-```shell
-curl http://localhost:2300/books \
- -H "Content-Type: application/json" \
- -H "Accept: application/json" \
- -d '{"book":{"title":"Hanami"}}' \
- -X POST
-```
-
-In order to make book payload available in `params`, we should enable this feature:
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- body_parsers :json
- end
- end
-end
-```
-
-Now `params.get(:book, :title)` returns `"Hanami"`.
-
-In case there is no suitable body parser for your format in Hanami, it is possible to declare a new one:
-
-```ruby
-# lib/foo_parser.rb
-class FooParser
- def mime_types
- ['application/foo']
- end
-
- def parse(body)
- # manually parse body
- end
-end
-```
-
-and subsequently register it:
-
-```ruby
-# apps/web/application.rb
-# ...
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- body_parsers FooParser.new
- # ...
- end
- end
-end
-```
diff --git a/source/guides/1.0/actions/rack-integration.md b/source/guides/1.0/actions/rack-integration.md
deleted file mode 100644
index aef3471b7..000000000
--- a/source/guides/1.0/actions/rack-integration.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-title: Guides - Request & Response
-version: 1.0
----
-
-# Rack Integration
-
-## Rack Environment
-
-Actions offer a high level API built on top of Rack.
-If we need to access raw data from Rack environment we can use `params.env`.
-
-## Rack Middleware
-
-Hanami mounts a very thin default middleware stack.
-Additional components can be mounted globally, at the application level, or locally.
-
-### Global Middleware
-
-If we need a component that wraps all the applications (under `apps/`), we can edit `config.ru` at the root of the project.
-
-```ruby
-# config.ru
-require './config/environment'
-require 'rack/auth/basic'
-
-use Rack::Auth::Basic
-run Hanami.app
-```
-
-### Application Middleware
-
-If we need a component that's only used by a specific application (under `apps/`), we can add it to the application's configuration.
-
-```ruby
-# apps/web/application.rb
-require 'rack/auth/basic'
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- middleware.use Rack::Auth::Basic
- end
- end
-end
-```
-
-### Action Middleware
-
-Sometimes we need a middleware only to be used for a set of well known resources.
-If we mount it at the global or application level the performance will start to degrade.
-Actions allow us to mount a fine grained middleware stack.
-
-```ruby
-# apps/web/controllers/sessions/create.rb
-require 'omniauth'
-
-module Web::Controllers::Sessions
- class Create
- include Web::Action
-
- use OmniAuth::Builder {
- # ...
- }
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-We can use the following syntax to mount different middleware that require arguments.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- use XMiddleware.new('x', 123)
- use YMiddleware.new
- use ZMiddleware
-
- def call(params)
- # ...
- end
- end
-end
-```
diff --git a/source/guides/1.0/actions/request-and-response.md b/source/guides/1.0/actions/request-and-response.md
deleted file mode 100644
index b44e55570..000000000
--- a/source/guides/1.0/actions/request-and-response.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: Guides - Request & Response
-version: 1.0
----
-
-# Request
-
-In order to access the metadata coming from a HTTP request, an action has a private object `request` that derives from `Rack::Request`.
-Here an example of some information that we can introspect.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- puts request.path_info # => "/dashboard"
- puts request.request_method # => "GET"
- puts request.get? # => true
- puts request.post? # => false
- puts request.xhr? # => false
- puts request.referer # => "http://example.com/"
- puts request.user_agent # => "Mozilla/5.0 Macintosh; ..."
- puts request.ip # => "127.0.0.1"
- end
- end
-end
-```
-
-
- Instantiating a request
for each incoming HTTP request can lead to minor performance degradation.
- As an alternative, please consider getting the same information from private action methods like accept?
or from the raw Rack environment params.env
.
-
-
-# Response
-
-The implicit return value of `#call` is a serialized `Rack::Response` (see [#finish](http://rubydoc.info/github/rack/rack/master/Rack/Response#finish-instance_method)):
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- end
- end
-end
-
-# It will return [200, {}, [""]]
-```
-
-It has private accessors to explicitly set status, headers and body:
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- self.status = 201
- self.body = 'Your resource has been created'
- self.headers.merge!({ 'X-Custom' => 'OK' })
- end
- end
-end
-
-# It will return [201, { "X-Custom" => "OK" }, ["Your resource has been created"]]
-```
-
-As shortcut we can use `#status`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- status 201, "Your resource has been created"
- end
- end
-end
-
-# It will return [201, {}, ["Your resource has been created"]]
diff --git a/source/guides/1.0/actions/sessions.md b/source/guides/1.0/actions/sessions.md
deleted file mode 100644
index b29371b3a..000000000
--- a/source/guides/1.0/actions/sessions.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: Guides - Action Sessions
-version: 1.0
----
-
-# Sessions
-
-## Enable Sessions
-
-Sessions are available in Hanami applications, but not enabled by default.
-If we want to turn on this feature, we just need to uncomment a line of code.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- sessions :cookie, secret: ENV['WEB_SESSIONS_SECRET']
- end
- end
-end
-```
-
-The first argument is the name of the adapter for the session storage.
-The default value is `:cookie`, that uses `Rack::Session::Cookie`.
-
-
-The name of the session adapter is the underscored version of the class name under Rack::Session
namespace.
-Example: :cookie
for Rack::Session::Cookie
.
-
-
-We can use a different storage compatible with Rack sessions.
-Let's say we want to use Redis. We should bundle `redis-rack` and specify the name of the adapter: `:redis`.
-Hanami is able to autoload the adapter and use it when the application is started.
-
-
-Custom storage technologies are autoloaded via require "rack/session/#{ adapter_name }"
.
-
-
-The second argument passed to `sessions` is a Hash of options that are **passed to the adapter**.
-We find only a default `:secret`, but we can specify all the values that are supported by the current adapter.
-
-## Usage
-
-Sessions behave like a Hash: we can read, assign and remove values.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- session[:b] # read
- session[:a] = 'foo' # assign
- session[:c] = nil # remove
- end
- end
-end
-```
diff --git a/source/guides/1.0/actions/share-code.md b/source/guides/1.0/actions/share-code.md
deleted file mode 100644
index e7f3a32aa..000000000
--- a/source/guides/1.0/actions/share-code.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-title: Guides - Action Share Code
-version: 1.0
----
-
-# Share Code
-
-Actions as objects have a lot of advantages but they make code sharing less intuitive.
-This section shares a few techniques to make this possible.
-
-## Prepare
-
-In our settings (`apps/web/application.rb`), there is a code block that allows us to share the code for **all the actions** of our application.
-When an action includes the `Web::Action` module, that block code is yielded within the context of that class.
-This is heavily inspired by Ruby Module and its `included` hook.
-
-Imagine we want to check if the current request comes from an authenticated user.
-
-We craft a module in `apps/web/controllers/authentication.rb`.
-
-```ruby
-# apps/web/controllers/authentication.rb
-module Web
- module Authentication
- def self.included(action)
- action.class_eval do
- before :authenticate!
- expose :current_user
- end
- end
-
- private
-
- def authenticate!
- halt 401 unless authenticated?
- end
-
- def authenticated?
- !!current_user
- end
-
- def current_user
- @current_user ||= UserRepository.new.find(session[:user_id])
- end
- end
-end
-```
-
-Once included by an action, it will set a [before callback](/guides/1.0/actions/control-flow) that executes `:authenticate!` for each request.
-If not logged in, a `401` is returned, otherwise the flow can go ahead and hit `#call`.
-It also exposes `current_user` for all the views (see [Exposures](/guides/1.0/actions/exposures)).
-
-It will be really tedious to include this module for all the actions of our app.
-We can use `controller.prepare` for the scope.
-
-```ruby
-# apps/web/application.rb
-require_relative './controllers/authentication'
-
-module Web
- class Application < Hanami::Application
- configure do
- controller.prepare do
- include Web::Authentication
- end
- end
- end
-end
-```
-
-
-Code included via prepare
is available for ALL the actions of an application.
-
-
-### Skipping A Callback
-
-Let's say we have included `Authentication` globally, but want to skip the execution of its callback for certain resources.
-A typical use case is to redirect unauthenticated requests to our sign in form.
-
-The solution is really simple and elegant at the same time: override that method.
-
-```ruby
-# apps/web/controllers/sessions/new.rb
-module Web::Controllers::Sessions
- class New
- include Web::Action
-
- def call(params)
- # ...
- end
-
- private
- def authenticate!
- # no-op
- end
- end
-end
-```
-
-The action will still try to invoke `:authenticate!`, because, technically speaking, **callbacks execution can't be skipped**.
-But if we override that method with an empty implementation, it does nothing and our non-signedin users can reach the wanted resource.
-
-## Module Inclusion
-
-Imagine we have a RESTful resource named `books`.
-There are several actions (`show`, `edit`, `update` and `destroy`) which need to find a specific book to perform their job.
-
-What if we want to DRY the code of all these actions?
-Ruby comes to our rescue.
-
-```ruby
-# apps/web/controllers/books/set_book.rb
-module Web::Controllers::Books
- module SetBook
- def self.included(action)
- action.class_eval do
- before :set_book
- end
- end
-
- private
-
- def set_book
- @book = BookRepository.new.find(params[:id])
- halt 404 if @book.nil?
- end
- end
-end
-```
-
-We have defined a module for our behavior to share. Let's include it in all the actions that need it.
-
-```ruby
-# apps/web/controllers/books/update.rb
-require_relative './set_book'
-
-module Web::Controllers::Books
- class Update
- include Web::Action
- include SetBook
-
- def call(params)
- # ...
- end
- end
-end
-```
-
diff --git a/source/guides/1.0/actions/testing.md b/source/guides/1.0/actions/testing.md
deleted file mode 100644
index 63f3378fc..000000000
--- a/source/guides/1.0/actions/testing.md
+++ /dev/null
@@ -1,310 +0,0 @@
----
-title: Guides - Action Testing
-version: 1.0
----
-
-# Testing
-
-Hanami pays a lot of attention to code testability and it offers advanced features to make our lives easier.
-The framework supports Minitest (default) and RSpec.
-
-## Unit Tests
-
-First of all, actions can be unit tested.
-That means we can instantiate, exercise and verify expectations **directly on actions instances**.
-
-```ruby
-# spec/web/controllers/dashboard/index_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/dashboard/index'
-
-describe Web::Controllers::Dashboard::Index do
- let(:action) { Web::Controllers::Dashboard::Index.new }
- let(:params) { Hash[] }
-
- it "is successful" do
- response = action.call(params)
- response[0].must_equal 200
- end
-end
-```
-
-In the example above, `action` is an instance of `Web::Controllers::Dashboard::Index`, we can invoke `#call` on it, passing a Hash of parameters.
-The [implicit returning value](/guides/1.0/actions/rack-integration) is a serialized Rack response.
-We're asserting that the status code (`response[0]`) is successful (equals to `200`).
-
-### Running Tests
-
-We can run the entire test suite or a single file.
-
-The default Rake task for the application serves for our first case: `bundle exec rake`.
-All the dependencies and the application code (actions, views, entities, etc..) are eagerly loaded.
-**Boot time is slow in this case.**
-
-
-The entire test suite can be run via default Rake task. It loads all the dependencies, and the application code.
-
-
-The second scenario can be done via: `ruby -Ispec spec/web/controllers/dashboard/index_spec.rb` (or `rspec spec/web/controllers/dashboard/index_spec.rb` if we use RSpec).
-When we run a single file example **only the framework and the application settings are loaded**.
-
-Please note the `require_relative` line in the example.
-It's **auto generated for us** and it's needed to load the current action under test.
-This mechanism allows us to run unit tests in **isolation**.
-**Boot time is magnitudes faster**.
-
-
-A single unit test can be run directly. It only loads the dependencies, but not the application code.
-The class under test is loaded via require_relative
, a line automatically generated for us.
-In this way we can have a faster startup time and a shorter feedback cycle.
-
-
-### Params
-
-When testing an action, we can easily simulate parameters and headers coming from the request.
-We just need to pass them as a Hash.
-Headers for Rack env such as `HTTP_ACCEPT` can be mixed with params like `:id`.
-
-The following test example uses both.
-
-```ruby
-# spec/web/controllers/users/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/show'
-
-describe Web::Controllers::Users::Show do
- let(:action) { Web::Controllers::Users::Show.new }
- let(:format) { 'application/json' }
- let(:user_id) { '23' }
-
- it "is successful" do
- response = action.call(id: user_id, 'HTTP_ACCEPT' => format)
-
- response[0].must_equal 200
- response[1]['Content-Type'].must_equal "#{ format }; charset=utf-8"
- response[2].must_equal ["ID: #{ user_id }"]
- end
-end
-```
-
-Here the corresponding production code.
-
-```ruby
-# apps/web/controllers/users/show.rb
-module Web::Controllers::Users
- class Show
- include Web::Action
-
- def call(params)
- puts params.class # => Web::Controllers::Users::Show::Params
- self.body = "ID: #{ params[:id] }"
- end
- end
-end
-```
-
-
-Simulating request params and headers is simple for Hanami actions. We pass them as a Hash
and they are transformed into an instance of Hanami::Action::Params
.
-
-
-### Exposures
-
-There are cases where we want to verify the internal state of an action.
-Imagine we have a classic user profile page, like depicted in the example above.
-The action asks for a record that corresponds to the given id, and then set a `@user` instance variable.
-How do we verify that the record is the one that we are looking for?
-
-Because we want to make `@user` available to the outside world, we're going to use an [_exposure_](/guides/1.0/actions/exposures).
-They are used to pass a data payload between an action and the corresponding view.
-When we do `expose :user`, Hanami creates a getter (`#user`), so we can easily assert if the record is the right one.
-
-```ruby
-# apps/web/controllers/users/show.rb
-module Web::Controllers::Users
- class Show
- include Web::Action
- expose :user, :foo
-
- def call(params)
- @user = UserRepository.new.find(params[:id])
- @foo = 'bar'
- end
- end
-end
-```
-
-We have used two _exposures_: `:user` and `:foo`, let's verify if they are properly set.
-
-```ruby
-# spec/web/controllers/users/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/show'
-
-describe Web::Controllers::Users::Show do
- before do
- @user = UserRepository.new.create(name: 'Luca')
- end
-
- let(:action) { Web::Controllers::Users::Show.new }
-
- it "is successful" do
- response = action.call(id: @user.id)
-
- response[0].must_equal 200
-
- action.user.must_equal @user
- action.exposures.must_equal({user: @user, foo: 'bar'})
- end
-end
-```
-
-
-The internal state of an action can be easily verified with exposures .
-
-
-### Dependency Injection
-
-During unit testing, we may want to use mocks to make tests faster or to avoid hitting external systems like databases, file system or remote services.
-Because we can instantiate actions during tests, there is no need to use testing antipatterns (eg. `any_instance_of`, or `UserRepository.new.stub(:find)`).
-Instead, we can just specify which collaborators we want to use via _dependency injection_.
-
-Let's rewrite the test above so that it does not hit the database.
-We're going to use RSpec for this example as it has a nicer API for mocks (doubles).
-
-```ruby
-# spec/web/controllers/users/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/show'
-
-RSpec.describe Web::Controllers::Users::Show do
- let(:action) { Web::Controllers::Users::Show.new(repository: repository) }
- let(:user) { User.new(id: 23, name: 'Luca') }
- let(:repository) { double('repository', find: user) }
-
- it "is successful" do
- response = action.call(id: user.id)
-
- expect(response[0]).to eq 200
- expect(action.user).to eq user
- expect(action.exposures).to eq({user: user})
- end
-end
-```
-
-We have injected the repository dependency which is a mock in our case.
-Here how to adapt our action.
-
-```ruby
-# apps/web/controllers/users/show.rb
-module Web::Controllers::Users
- class Show
- include Web::Action
- expose :user
-
- def initialize(repository: UserRepository.new)
- @repository = repository
- end
-
- def call(params)
- @user = @repository.find(params[:id])
- end
- end
-end
-```
-
-
-Please be careful using doubles in unit tests. Always verify that the mocks are in a true representation of the corresponding production code.
-
-
-
-### Flash messages
-
-In your action tests, you can check `flash` messages too. For this, you can use `exposures` method for getting all flash data.
-
-The following test example uses this method.
-
-```ruby
-# spec/web/controllers/users/create_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/create'
-
-describe Web::Controllers::Users::Create do
- let(:action) { Web::Controllers::Users::Create.new }
- let(:user_params) { name: 'Luca' }
-
- it "is successful" do
- response = action.call(id: user_params)
- flash = action.exposures[:flash]
-
- flash[:info].must_equal 'User was successfully created'
- end
-end
-```
-
-## Requests Tests
-
-Unit tests are a great tool to assert that low level interfaces work as expected.
-We always advise combining them with integration tests.
-
-In the case of Hanami web applications, we can write features (aka acceptance tests) with Capybara, but what do we use when we are building HTTP APIs?
-The tool that we suggest is `rack-test`.
-
-Imagine we have an API application mounted at `/api/v1` in our `Hanami::Container`.
-
-```ruby
-# config/environment.rb
-# ...
-Hanami::Container.configure do
- mount ApiV1::Application, at: '/api/v1'
- mount Web::Application, at: '/'
-end
-```
-
-Then we have the following action.
-
-```ruby
-# apps/api_v1/controllers/users/show.rb
-module ApiV1::Controllers::Users
- class Show
- include ApiV1::Action
- accept :json
-
- def call(params)
- user = UserRepository.new.find(params[:id])
- self.body = JSON.generate(user.to_h)
- end
- end
-end
-```
-
-In this case we don't care too much about the internal state of the action, but about the output visible to the external world.
-This is why we haven't set `user` as an instance variable and why we haven't exposed it.
-
-```ruby
-# spec/api_v1/requests/users_spec.rb
-require 'spec_helper'
-
-describe "API V1 users" do
- include Rack::Test::Methods
-
- before do
- @user = UserRepository.new.create(name: 'Luca')
- end
-
- # app is required by Rack::Test
- def app
- Hanami.app
- end
-
- it "is successful" do
- get "/api/v1/users/#{ @user.id }"
-
- last_response.must_be :ok?
- last_response.body.must_equal(JSON.generate(@user.to_h))
- end
-end
-```
-
-
-Please avoid test doubles when writing full integration tests, as we want to verify that the whole stack is behaving as expected.
-
diff --git a/source/guides/1.0/architecture/overview.md b/source/guides/1.0/architecture/overview.md
deleted file mode 100644
index dcadcc68d..000000000
--- a/source/guides/1.0/architecture/overview.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-title: "Guides - Architectures: Container"
-version: 1.0
----
-
-# Architectures
-
-Hanami is based on two principles: [Clean Architecture](https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html) and [Monolith First](http://martinfowler.com/bliki/MonolithFirst.html).
-
-## Clean Architecture
-
-The main purpose of this architecture is to enforce a **separation of concerns** between the **core** of our product and the **delivery mechanisms**.
-The first is expressed by the set of **use cases** that our product implements, while the latter are interfaces to make these features available to the outside world.
-
-When we generate a new project we can find two important directories: `lib/` and `apps/`.
-They are home to the main parts described above.
-
-### Application Core
-
-We implement a set of functionalities, without worrying about how they can be exposed to the outside world.
-This is the **cornerstone** of our product, and we want to be careful on how we manage dependencies for it.
-
-`Hanami::Model` is the default choice for persisting our Ruby objects.
-This is a _soft-dependency_, it can be removed from our `Gemfile` and replaced with something else.
-
-Let's have a look at how the `lib/` directory appears for a new generated project called `bookshelf` that uses `Hanami::Model`.
-
-```shell
-% tree lib
-lib
-βββ bookshelf
-βΒ Β βββ entities
-βΒ Β βββ mailers
-βΒ Β βΒ Β βββ templates
-βΒ Β βββ repositories
-βββ bookshelf.rb
-
-5 directories, 1 file
-```
-
-The idea is to develop our application like a Ruby gem.
-
-The `lib/bookshelf.rb` file is the entry point for our application, when we require this file, we require and initialize all the code under `lib/`.
-
-There are two important directories:
-
- * `lib/bookshelf/entities`
- * `lib/bookshelf/repositories`
-
-They contain [entities](/guides/1.0/models/entities) that are Ruby objects at the core of our model domain, and they aren't aware of any persistence mechanism.
-For this purpose we have a separate concept, [repositories](/guides/1.0/models/repositories), which are a mediator between our entities and the underlying database.
-
-For each entity named `Book` we can have a `BookRepository`.
-
-We can add as many directories that we want, such as `lib/bookshelf/interactors` to implement our use cases.
-
-### Delivery Mechanisms
-
-Hanami generates a default application named `Web`, which lives under `apps/web`.
-This application **depends** on the core of our product, as it uses entities, repositories and all the other objects defined there.
-
-It's used as web delivery mechanism, for our features.
-
-```shell
-% tree apps/web
-apps/web
-βββ application.rb
-βββ assets
-βΒ Β βββ favicon.ico
-βΒ Β βββ images
-βΒ Β βββ javascripts
-βΒ Β βββ stylesheets
-βββ config
-βΒ Β βββ routes.rb
-βββ controllers
-βββ templates
-βΒ Β βββ application.html.erb
-βββ views
- βββ application_layout.rb
-
-8 directories, 5 files
-```
-
-Let's have a quick look at this code.
-
-The file `apps/web/application.rb` contains a Hanami application named `Web::Application`, here we can configure all the settings for this **component** of our project.
-Directories such as `apps/web/controllers`, `views` and `templates` will contain our [actions](/guides/1.0/actions/overview), [views](/guides/1.0/views/overview) and [templates](/guides/1.0/views/templates).
-
-Web assets such as javascripts and stylesheets will be automatically served by the application.
-
-## Monolith First
-
-Our default application `Web` can be used as a UI interface for our customers.
-At a certain point in our story, we want to manage our users with an admin panel.
-
-We know that the set of features that we're going to introduce doesn't belong to our main UI (`Web`).
-On the other hand, it's **too early** for us to implement a microservices architecture, only for the purpose of helping our users reset their password.
-
-Hanami has a solution for our problem: we can generate a new app that lives in the same Ruby process, but it's a separated component.
-
-```shell
-% bundle exec hanami generate app admin
-```
-
-This command MUST be run from the root of our project. It will generate a new application (`Admin::Application`) under `apps/admin`.
-
-In the late stages of our product life-cycle, we could decide to extract this into a standalone component.
-We would just need to move everything under `apps/admin` into another repository and deploy it separately.
-
-## Anatomy Of A Project
-
-We have already examined `lib/` and `apps/`, but there are other parts of a newly generated project that deserve to be explained.
-
-```shell
-% tree -L 1
-.
-βββ Gemfile
-βββ Gemfile.lock
-βββ Rakefile
-βββ apps
-βββ config
-βββ config.ru
-βββ db
-βββ lib
-βββ spec
-```
-
-Let's quickly introduce them:
-
- * `Gemfile` and `Gemfile.lock` are [Bundler](http://bundler.io) artifacts
- * `Rakefile` describes Rake task for our project.
- * `config/` contains an important file `config/environment.rb`, which is the **entry point** for our project.
- By requiring it, we'll preload our dependencies (Ruby gems), Hanami frameworks and our code.
- * `config.ru` is a file that describes how a Rack server must run our applications.
- * `db/` contains database files (for File System adapter or SQLite).
- When our project uses a SQL database it also contains `db/migrations` and `db/schema.sql`.
- * `spec/` contains unit and acceptance tests.
diff --git a/source/guides/1.0/assets/compressors.md b/source/guides/1.0/assets/compressors.md
deleted file mode 100644
index b7820c8af..000000000
--- a/source/guides/1.0/assets/compressors.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: Guides - Assets Compressors
-version: 1.0
----
-
-# Assets
-
-## Compressors
-
-Assets compression (aka minification) is a process to shrink the file size of a file in order to reduce the time that a browser needs to download it.
-Usually, it's applied to javascripts and stylesheets.
-
-In order to set one of the following engines, we need to open `apps/web/application.rb` and write:
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- assets do
- javascript_compressor :builtin
- stylesheet_compressor :builtin
-
- # ...
- end
- end
- end
-end
-```
-
-If we want to skip compression, just comment one or both the lines above.
-
-### JavaScript
-
-We support the following engines:
-
- * `:builtin` - It isn't efficient like the other algorithms, but it's a good starting point because it's written in **pure Ruby** and **it doesn't require external dependencies**.
- * `:yui` - It's based on [Yahoo! YUI Compressor](http://yui.github.io/yuicompressor). It requires [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and Java 1.4+
- * `:uglifier` - It's based on [UglifyJS2](http://lisperator.net/uglifyjs). It requires [uglifier](https://rubygems.org/gems/uglifier) gem and Node.js
- * `:closure` - It's based on [Google Closure Compiler](https://developers.google.com/closure/compiler). It requires [`closure-compiler`](https://rubygems.org/gems/closure-compiler) gem and Java
-
-
- In order to use :yui
, :uglifier
and :closure
compressors, you need to add the corresponding gem to Gemfile
.
-
-
-### Stylesheet
-
-We support the following engines:
-
- * `:builtin` - It isn't efficient like the other algorithms, but it's a good starting point because it's written in **pure Ruby** and **it doesn't require external dependencies**.
- * `:yui` - It's based on [Yahoo! YUI Compressor](http://yui.github.io/yuicompressor). It requires [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and Java 1.4+
- * `:sass` - It's based on [Sass](http://sass-lang.com). It requires [sass](https://rubygems.org/gems/sass) gem
-
-
- In order to use :yui
, and :sass
compressors, you need to add the corresponding gem to Gemfile
.
-
-
-### Custom Compressors
-
-We can use our own compressor for **both JS and CSS**.
-It **MUST** respond to `#compress(filename)` and return a `String` with the minification output.
-
-```ruby
-class MyCustomJavascriptCompressor
- def compress(filename)
- # ...
- end
-end
-```
-
-Then we can use it with our configuration:
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- assets do
- javascript_compressor MyCustomJavascriptCompressor.new
- stylesheet_compressor :builtin
-
- # ...
- end
- end
- end
-end
-```
diff --git a/source/guides/1.0/assets/content-delivery-network.md b/source/guides/1.0/assets/content-delivery-network.md
deleted file mode 100644
index 2a10a5bc5..000000000
--- a/source/guides/1.0/assets/content-delivery-network.md
+++ /dev/null
@@ -1,119 +0,0 @@
----
-title: Guides - Assets Content Delivery Network (CDN)
-version: 1.0
----
-
-# Assets
-
-## Content Delivery Network (CDN)
-
-A Hanami application can serve assets from a [Content Delivery Network](https://en.wikipedia.org/wiki/Content_delivery_network) (CDN).
-This feature is useful in _production_ environment, where we want to speed up static assets serving.
-
-In order to take advantage of this feature, we need to specify CDN settings.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- # ...
- configure :production do
- scheme 'https'
- host 'bookshelf.org'
- port 443
-
- assets do
- # ...
- fingerprint true
-
- # CDN settings
- scheme 'https'
- host '123.cloudfront.net'
- port 443
- end
- end
- end
-end
-```
-
-Once _CDN mode_ is on, all the [asset helpers](/guides/1.0/helpers/assets) will return **absolute URLs**.
-
-```erb
-<%= stylesheet 'application' %>
-```
-
-```html
-
-```
-
-## Subresource Integrity
-
-A CDN can dramatically improve page speed, but it can potentially open a security breach.
-If the CDN that we're using is compromised and serves evil javascript or stylesheet files, we're exposing our users to security attacks like Cross Site Scripting (XSS).
-
-To solve this problem, browsers vendors introduced a defense called [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
-
-When enabled, the browser verifies that the checksum of the downloaded file, matches with the declared one.
-
-### From A CDN
-
-If we're using jQuery from their CDN, we should find the checksum of the `.js` file on their website and write:
-
-```erb
-<%= javascript 'https://code.jquery.com/jquery-3.1.0.min.js', integrity: 'sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=' %>
-```
-
-The output will be:
-
-```html
-
-```
-
-### Local Assets
-
-The security problem described above doesn't concern only CDNs, but local files too.
-Imagine we have a compromised file system and someone was able to replace our javascripts with evil files: we would be vulnerable to the same kind of attack.
-
-As a defense against this security problem, Hanami **enables Subresource Integrity by default in production.**
-When we [precompile assets](/guides/1.0/command-line/assets) at deploy time, Hanami calculates the checksum of all our assets and it adds a special HTML attribute `integrity` to our asset tags like `
-```
-
-### Settings
-
-To turn off this feature, or to configure it, please have a look at the `production` block in `apps/web/application.rb`
-
-```ruby
-module Web
- class Application < Hanami::Application
- configure :production do
- assets do
- # ...
- subresource_integrity :sha256
- end
- end
- end
-end
-```
-
-By removing or commenting that line, the feature is turned off.
-
-We can choose one or more checksum algorithms:
-
-```ruby
-subresource_integrity :sha256, :sha512
-```
-
-With this setting, Hanami will render `integrity` HTML attribute with two values: one for `SHA256` and one for `SHA512`.
-
-```html
-
-```
-
-**Please note** that checksum calculations are CPU intensive, so adding an additional `subresource_integrity` scheme will extend the time it takes to _precompile assests_, and therefore deploy. We suggest leaving the default setting (`:sha256`).
diff --git a/source/guides/1.0/assets/overview.md b/source/guides/1.0/assets/overview.md
deleted file mode 100644
index 0fe3f7a31..000000000
--- a/source/guides/1.0/assets/overview.md
+++ /dev/null
@@ -1,255 +0,0 @@
----
-title: Guides - Assets Overview
-version: 1.0
----
-
-# Assets
-
-Hanami supports powerful features for web assets.
-
-## Configuration
-
-Each application can have its own separated assets settings in application configuration.
-
-### Compile Mode
-
-Toggle this value, to determine if the application must preprocess or copy assets from sources to public directory.
-It's turned on by default in _development_ and _test_ environments, but turned off for _production_.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- assets do
- # compile true, enabled by default
- end
- end
-
- configure :production do
- assets do
- compile false
- end
- end
- end
-end
-```
-
-### Fingerprint Mode
-
-In order to force browsers to cache the right copy of an asset, during the deploy, Hanami creates a copy of each file by [appending its checksum](/guides/1.0/command-line/assets) to the file name.
-
-We can control this feature via application configuration.
-It's turned on by default only in _production_ environment.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- assets do
- # fingerprint false, disabled by default
- end
- end
-
- configure :production do
- assets do
- fingerprint true
- end
- end
- end
-end
-```
-
-If enabled, [assets helpers](/guides/1.0/helpers/assets) will generate checksum relative URLs.
-
-```erb
-<%= javascript 'application' %>
-```
-
-```html
-
-```
-
-## Serve Static Assets
-
-It can dynamically serve them during development.
-It mounts `Hanami::Static` middleware in project Rack stack. This component is conditionally activated, if the environment variable `SERVE_STATIC_ASSETS` equals to `true`.
-
-By default, new projects are generated with this feature enabled in _development_ and _test_ mode, via their corresponding `.env.*` files.
-
-```
-# .env.development
-# ...
-SERVE_STATIC_ASSETS="true"
-```
-
-Hanami assumes that projects in _production_ mode are deployed using a web server like Nginx that is responsible to serve them without even hitting the Ruby code.
-
-
- Static assets serving is enabled by default in development and test environments, but turned off for production .
-
-
-There are cases where this assumption isn't true. For instance, Heroku requires Ruby web apps to serve static assets.
-To enable this feature in production, just make sure that this special environment variable is set to `true` (in `.env` or `.env.production`).
-
-### What Does It Mean To Serve Static Assets With Hanami?
-
-As mentioned above, when this feature is enabled, a special middleware is added in front of the project Rack stack: `Hanami::Static`.
-
-Incoming requests can generate the following use cases
-
-#### Fresh Asset
-
-```
-GET /assets/application.js
-```
-
-It copies the `apps/web/assets/javascripts/application.js` to `public/assets/application.js` and then serves it.
-
-
- Assets are copied only if the destination path does NOT exist (eg. public/assets/application.js
).
- If it DOES exist, the asset is only served, without copying it.
-
-
-
- When an application has turned OFF asset compilation (Compile mode), Hanami won't copy the file.
-
-
-#### Stale Asset
-
-This could happen in _development_ mode. When we require an asset the first time it gets copied to the `public/` directory. Then when we edit the source file, the destination file becomes stale.
-
-```
-GET /assets/application.js
-# edit the original file: apps/web/assets/javascripts/application.js
-# then require it again
-GET /assets/application.js
-```
-
-It copies the source into the destination file **again** (`public/assets/application.js`) and then serves it.
-
-#### Precompiled Asset
-
-Let's say we use Sass to write our stylesheets.
-
-```
-GET /assets/application.css
-```
-
-It preprocess the `apps/web/assets/stylesheet/application.css.sass` to `public/assets/application.css` and then serves it.
-
-#### Dynamic Resource
-
-```
-GET /books/23
-```
-
-This isn't a static file available under `public/`, so the control passes to the backend that hits the appropriate action.
-
-#### Missing Resource
-
-```
-GET /unknown
-```
-
-This isn't a static file or a dynamic resource, the project returns a `404 (Not Found)`.
-
-## Sources
-
-Each application has a separated set of directories where its assets can be found.
-Assets are recursively searched under these paths.
-
-New projects have a default directory where application assets can be put:
-
-```
-% tree apps/web/assets
-apps/web/assets
-βββ favicon.ico
-βββ images
-βββ javascripts
-βββ stylesheets
-
-3 directories, 1 file
-```
-
-We can add as many directories we want under it (eg. `apps/web/assets/fonts`).
-
-
- For a given application named Web
, the default asset directory is apps/web/assets
-
-
-### Adding Sources
-
-If we want to add other sources for a given application, we can specify them in the configuration.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- assets do
- # apps/web/assets is added by default
- sources << [
- 'vendor/assets'
- ]
- end
- end
- end
-end
-```
-
-This will add `apps/web/vendor/assets` and all its subdirectories.
-
-
- Hanami looks recursively through the asset sources. In order to NOT accidentally disclose sensitive files like secrets or source code, please make sure that these sources directories ONLY contain web assets.
-
-
-## Third Party Gems
-
-Hanami allows developers to use [Rubygems](https://rubygems.org) as a way to distribute web assets and make them available to Hanami applications.
-
-Third party gems can be maintained by developers who want to bring frontend framework support to Hanami.
-Let's say we want to build an `hanami-emberjs` gem.
-
-```shell
-% tree .
-# ...
-βββ lib
-βΒ Β βββ hanami
-βΒ Β βββ emberjs
-βΒ Β βΒ Β βββ dist
-βΒ Β βΒ Β βΒ Β βββ ember.js
-βΒ Β βΒ Β βΒ Β βββ ember.min.js
-βΒ Β βΒ Β βββ version.rb
-βΒ Β βββ emberjs.rb
-βββ hanami-emberjs.gemspec
-# ...
-```
-
-We put **only** the assets that we want to serve in an **arbitrary** directory.
-Then we add it to `Hanami::Assets.sources`.
-
-```ruby
-# lib/hanami/emberjs.rb
-require 'hanami/assets'
-
-module Hanami
- module Emberjs
- require 'hanami/emberjs/version'
- end
-end
-
-Hanami::Assets.sources << __dir__ + '/emberjs/source'
-```
-
-When an application requires `'hanami/emberjs'`, that directory will be added to the sources where Hanami can search for assets.
-
-```erb
-<%= javascript 'ember' %>
-```
-
-Then we can use the `javascript` [helper](/guides/1.0/helpers/assets) to include `ember.js` in our application.
diff --git a/source/guides/1.0/assets/preprocessors.md b/source/guides/1.0/assets/preprocessors.md
deleted file mode 100644
index 0f98c5e17..000000000
--- a/source/guides/1.0/assets/preprocessors.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-title: Guides - Assets Preprocessors
-version: 1.0
----
-
-# Assets
-
-## Preprocessors
-
-Hanami is able to run assets preprocessors and **lazily compile** them under `public/assets`.
-
-Imagine to have `application.css.scss` in `apps/web/assets/stylesheets` and `reset.css` under
-`apps/web/vendor/stylesheets`.
-
-**The extensions structure is important.**
-The first one is mandatory and it's used to understand which asset type we are
-handling: `.css` for stylesheets.
-The second one is optional and it's for a preprocessor: `.scss` for Sass.
-
-
- For a given asset application.css.scss
, the last extension (.scss
) is used to determine the right preprocessor.
-
-
-
- Preprocessors are optional, an application can work with plain javascripts or stylesheets. In this case we have to name our assets with only one extension (eg application.css
).
-
-
-```ruby
-# apps/web/application.rb
-require 'sass'
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- assets do
- sources << [
- # apps/web/assets is added by default
- 'vendor/assets' # app/web/vendor/assets
- ]
- end
- end
- end
-end
-```
-
-From a template we do:
-
-```erb
-<%= stylesheet 'reset', 'application' %>
-```
-
-When we'll load the page the compiler will preprocess or copy the assets into `public/assets`.
-
-```shell
-% tree public
-public/
-βββ assets
- βββ application.css
- βββ reset.css
-```
-
-Preprocessors will compile/copy assets only if the [_Compile mode_](/guides/1.0/assets/overview) is on.
-
-
- Preprocessors are enabled by default in development and test environments.
-
-
-For performance reasons, this feature is turned off in _production_ env, where we should [precompile](/guides/1.0/command-line/assets) our assets.
-
-### Preprocessors Engines
-
-Hanami uses [Tilt](https://github.com/rtomayko/tilt) to provide support for the most common preprocessors, such as [Sass](http://sass-lang.com/) (including `sassc-ruby`), [Less](http://lesscss.org/), ES6, [JSX](https://jsx.github.io/), [CoffeScript](http://coffeescript.org), [Opal](http://opalrb.org), [Handlebars](http://handlebarsjs.com), [JBuilder](https://github.com/rails/jbuilder).
-
-In order to use one or more of them, be sure to include the corresponding gem into your `Gemfile` and require the library.
-
-```ruby
-# Gemfile
-# ...
-gem 'sass'
-```
-
-
- Some preprocessors may require Node.js. Please check the documentation.
-
-
-#### EcmaScript 6
-
-We strongly suggest to use [EcmaScript 6](http://es6-features.org/) for your next project, because that is the next version of JavaScript.
-It isn't fully [supported](https://kangax.github.io/compat-table/es6/) yet by browser vendors, but this is changing quickly.
-
-As of today, you need to transpile ES6 code into something understandable by current browsers, which is ES5.
-For this purpose we support [Babel](https://babeljs.io).
-
-
- Babel requires Node.js.
-
diff --git a/source/guides/1.0/assets/use-your-own-assets-management-tool.md b/source/guides/1.0/assets/use-your-own-assets-management-tool.md
deleted file mode 100644
index b74bad002..000000000
--- a/source/guides/1.0/assets/use-your-own-assets-management-tool.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: Guides - Use Your Own Assets Management
-version: 1.0
----
-
-# Use Your Own Assets Management
-
-Hanami tries to cover basic use cases for assets management: [(pre)compilation](/guides/1.0/assets/overview/#compile-mode), [compression](/guides/1.0/assets/compressors), [fingerprinting](/guides/1.0/assets/overview/#fingerprint-mode), [Content Delivery Network (CDN)](/guides/1.0/assets/content-delivery-network) with [Subresource Integrity](/guides/1.0/assets/content-delivery-network/#subresource-integrity).
-
-If it still doesn't fit your needs, you can use your own assets management tool such as Webpack.
-
-## Deployment
-
-To do so, please organize the assets according to your assets management tool and **don't** run `bundle exec hanami assets precompile` when deploying your project, but follow the instructions of your assets management software.
-
-Please remember that for compatibility with the [Ruby server hosting ecosystem](/guides/1.0/projects/rake/#ruby-server-hosting-ecosystem-compatibility), we make available a special Rake task `assets:precompile`, which is run automatically by SaaS vendors.
-If this is your situation, you may want override this task in the `Rakefile` of your project, with something more useful for you.
diff --git a/source/guides/1.0/command-line/applications.md b/source/guides/1.0/command-line/applications.md
deleted file mode 100644
index 2b5729c33..000000000
--- a/source/guides/1.0/command-line/applications.md
+++ /dev/null
@@ -1,36 +0,0 @@
----
-title: "Guides - Command Line: Applications"
-version: 1.0
----
-
-# Applications
-
-We can generate a new project via `hanami new`, followed by the name that we want to use.
-
-```shell
-% hanami new bookshelf
-```
-
-## Database
-
-The default database engine is SQLite.
-
-We can use the `--database` argument to let Hanami to generate code for a specific database.
-
-It supports:
-
- * `postgres`
- * `postgresql`
- * `sqlite` (default)
- * `sqlite3`
- * `mysql`
- * `mysql2`
-
-## Testing Framework
-
-The default testing framework is Minitest.
-
-We can use the `--test` argument to specify a different framework, from the list below:
-
- * `minitest` (default)
- * `rspec`
diff --git a/source/guides/1.0/command-line/assets.md b/source/guides/1.0/command-line/assets.md
deleted file mode 100644
index 991cf3704..000000000
--- a/source/guides/1.0/command-line/assets.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-title: "Guides - Command Line: Assets"
-version: 1.0
----
-
-# Assets
-
-We can manage assets via the command line.
-
-## Precompile
-
-This command is useful for **deployment** purposes.
-
-```shell
-% bundle exec hanami assets precompile
-```
-
-The first step it precompiles and copies all the assets from all the applications and third party gems under `public/assets/` directory.
-
-Then it [compress](/guides/1.0/assets/compressors) all the javascripts and stylesheets, in order to save browsers bandwidth.
-
-As last thing, it generates a copy of each asset, by appending its checksum to the file name.
-This trick makes assets cacheable by browsers.
-
-It generates a fingeprint manifest that lists all the assets and their checksum counterpart.
-
-```shell
-% cat public/assets.json
-{
- # ...
- "/assets/application.css":"/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css"
-}
-```
-
-This is used by assets helpers to resolve an asset name into a relative path.
-
-## Example
-
-Let's say we have a project with three applications: `admin`, `metrics` and `web`.
-
-```ruby
-# config/environment.rb
-# ...
-Hanami::Container.configure do
- mount Metrics::Application, at: '/metrics'
- mount Admin::Application, at: '/admin'
- mount Web::Application, at: '/'
-end
-```
-
-They have the following sources:
-
- * Admin: `apps/admin/assets`
- * Metrics: `apps/metrics/assets`
- * Web: `apps/web/assets`, `apps/web/vendor/assets`
-
-Furtermore, they all depend on Ember.js, which is distributed by an imaginary gem named `hanami-ember`.
-
-```shell
-% tree .
-βββ apps
-βΒ Β βββ admin
-βΒ Β βΒ Β βββ assets
-βΒ Β βΒ Β βΒ Β βββ js
-βΒ Β βΒ Β βΒ Β βββ application.js
-βΒ Β βΒ Β βΒ Β βββ zepto.js
-# ...
-βΒ Β βββ metrics
-βΒ Β βΒ Β βββ assets
-βΒ Β βΒ Β βΒ Β βββ javascripts
-βΒ Β βΒ Β βΒ Β βββ dashboard.js.es6
-# ...
-βΒ Β βββ web
-βΒ Β βββ assets
-βΒ Β βΒ Β βββ images
-βΒ Β βΒ Β βΒ Β βββ bookshelf.jpg
-βΒ Β βΒ Β βββ javascripts
-βΒ Β βΒ Β βββ application.js
-# ...
-βΒ Β βββ vendor
-βΒ Β βββ assets
-βΒ Β βββ javascripts
-βΒ Β βββ jquery.js
-# ...
-```
-
-When we run `hanami assets precompile` on our server, here's the output.
-
-```shell
-% tree public
-public
-βββ assets
-βΒ Β βββ admin
-βΒ Β βΒ Β βββ application-28a6b886de2372ee3922fcaf3f78f2d8.js
-βΒ Β βΒ Β βββ application.js
-βΒ Β βΒ Β βββ ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js
-βΒ Β βΒ Β βββ ember-source-e74117fc6ba74418b2601ffff9eb1568.js
-βΒ Β βΒ Β βββ ember-source.js
-βΒ Β βΒ Β βββ ember.js
-βΒ Β βΒ Β βββ zepto-ca736a378613d484138dec4e69be99b6.js
-βΒ Β βΒ Β βββ zepto.js
-βΒ Β βββ application-d1829dc353b734e3adc24855693b70f9.js
-βΒ Β βββ application.js
-βΒ Β βββ bookshelf-237ecbedf745af5a477e380f0232039a.jpg
-βΒ Β βββ bookshelf.jpg
-βΒ Β βββ ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js
-βΒ Β βββ ember-source-e74117fc6ba74418b2601ffff9eb1568.js
-βΒ Β βββ ember-source.js
-βΒ Β βββ ember.js
-βΒ Β βββ jquery-05277a4edea56b7f82a4c1442159e183.js
-βΒ Β βββ jquery.js
-βΒ Β βββ metrics
-βΒ Β βββ dashboard-7766a63ececc63a7a629bfb0666e9c62.js
-βΒ Β βββ dashboard.js
-βΒ Β βββ ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js
-βΒ Β βββ ember-source-e74117fc6ba74418b2601ffff9eb1568.js
-βΒ Β βββ ember-source.js
-βΒ Β βββ ember.js
-βββ assets.json
-```
-
-
- The structure of the output directories in public/assets
, reflects the path prefix of each application. The default application named Web
, is mounted at /
, so the output directory is public/assets
and their base URL is /assets
(eg. /assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js
).
- Simirarly, for an application Admin
mounted at /admin
, the assets will be placed under public/assets/admin
and reachable at /assets/admin/application-28a6b886de2372ee3922fcaf3f78f2d8.js
.
-
diff --git a/source/guides/1.0/command-line/database.md b/source/guides/1.0/command-line/database.md
deleted file mode 100644
index 5d7dbbb6f..000000000
--- a/source/guides/1.0/command-line/database.md
+++ /dev/null
@@ -1,130 +0,0 @@
----
-title: "Guides - Command Line: Database"
-version: 1.0
----
-
-# Database
-
-We can manage our database via the command line.
-
-**The following commands can be only used with the SQL adapter and with the following databases:**
-
- * PostgreSQL
- * MySQL
- * SQLite3
-
-The [adapter](/guides/1.0/models/overview) is set in `lib/bookshelf.rb`.
-It uses an environment variable, defined in the `.env.*` files at the root of the project.
-
-## Create
-
-With `db create` we can create the database for the current environment.
-
-```shell
-% bundle exec hanami db create
-```
-
-To be able to run tests, test database has to be explicitly created
-
-```shell
-% HANAMI_ENV=test bundle exec hanami db create
-```
-
-In order to preserve production data, this command can't be run in the production environment.
-
-## Drop
-
-With `db drop` we can drop the existing database for the current environment.
-
-```shell
-% bundle exec hanami db drop
-```
-
-In order to preserve production data, this command can't be run in the production environment.
-
-## Migrate
-
-With `db migrate` we can run [migrations](/guides/1.0/migrations/overview) found in `db/migrations`.
-
-Given the following migrations:
-
-```shell
-% tree db/migrations
-db/migrations
-βββ 20150613165259_create_books.rb
-βββ 20150613165900_create_authors.rb
-```
-
-We run `db migrate`, then the database _version_ becomes `20150613165900`, which is the maximum timestamp from the migrations above.
-
-```shell
-% bundle exec hanami db migrate # Migrates to max migration (20150613165900)
-```
-
-This command accepts an optional argument to specify the target version.
-For instance, if we want to **rollback** the changes from `20150613165900_create_authors.rb`, we can migrate _**"down"**_.
-
-```shell
-% bundle exec hanami db migrate 20150613165259 # Migrates (down) to 20150613165259
-```
-
-**This command is available in ALL the environments and ALL the SQL databases.**
-
-## Prepare
-
-Prepares database for the current environment. This command can't be run in the production environment.
-
-When we run `db prepare` it:
-
- * Creates the database
- * Loads SQL dump (if any, see `db apply`)
- * Runs pending migrations
-
-```shell
-% bundle exec hanami db prepare
-```
-
-This command SHOULD be used as a database setup command.
-
-## Apply
-
-This is an experimental feature.
-When an application is developed after years, it accumulates a large number of migrations, this slows down database operations for development and test (CI).
-
-Because it does destructive changes to files under SCM, this is only allowed in development mode.
-
-When we run `db apply`, it:
-
- * Runs pending migrations
- * Dumps a fresh schema into `db/schema.sql`
- * Deletes all the migrations from `db/migrations`
-
-```shell
-% bundle exec hanami db apply
-```
-
-This command is available only in the development environment.
-
-## Version
-
-Prints current database version. Given the following migrations:
-
-```shell
-% tree db/migrations
-db/migrations
-βββ 20150613165259_create_books.rb
-βββ 20150613165900_create_authors.rb
-```
-
-When we migrate the database:
-
-```shell
-% bundle exec hanami db migrate
-```
-
-We can then ask for the current version:
-
-```shell
-% bundle exec hanami db version
-20150613165900
-```
diff --git a/source/guides/1.0/command-line/destroy.md b/source/guides/1.0/command-line/destroy.md
deleted file mode 100644
index 45c3729da..000000000
--- a/source/guides/1.0/command-line/destroy.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "Guides - Command Line: Destroy"
-version: 1.0
----
-
-# Destroy
-
-Hanami has convenient [code generators](/guides/1.0/command-line/generators) to speed up our development process.
-If we commit a mistake, we can destroy what we just generated via `hanami destroy` command.
-
-## Applications
-
-With the Container architecture, we can have multiple Hanami applications running under `apps/`.
-We can [generate new applications](/guides/1.0/command-line/generators) for different components that we want to add to our project.
-
-To destroy one of them:
-
-```shell
-% bundle exec hanami destroy app admin
-```
-
-This removes an application named `Admin` under `apps/admin`.
-
-## Actions
-
-We can destroy an action along with the corresponding view, template, route and test code with one command.
-
-```shell
-% bundle exec hanami destroy action web books#show
-```
-
-The first argument, `web`, is the name of the target application in a Container architecture.
-**It must be omitted if used within an Application architecture:**
-
-```shell
-% bundle exec hanami destroy action books#show
-```
-
-The argument `books#show` is the name of the controller and the action separated by the number sign (`#`).
-
-## Models
-
-We can destroy a model.
-
-```shell
-% bundle exec hanami destroy model book
-```
-
-It removes an entity with the corresponding repository and test code.
-
-## Migrations
-
-We can destroy a migration.
-
-```shell
-% bundle exec hanami destroy migration create_books
-```
-
-It deletes the migration with the corresponding name (eg. `db/migrations/20150621181347_create_books.rb`).
-
-## Mailers
-
-We can destroy a mailer.
-
-```shell
-% bundle exec hanami destroy mailer welcome
-```
-
-It removes the mailer, and the associated templates.
diff --git a/source/guides/1.0/command-line/generators.md b/source/guides/1.0/command-line/generators.md
deleted file mode 100644
index 4a3f3a6a2..000000000
--- a/source/guides/1.0/command-line/generators.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: "Guides - Command Line: Generators"
-version: 1.0
----
-
-# Generators
-
-Hanami has convenient code generators to speed up our development process.
-
-## Applications
-
-With Hanami architecture, we can have multiple Hanami applications running under `apps/`.
-The default application is called `Web` and lives under `apps/web`.
-
-We can generate new applications for different components that we want to add to our project.
-
-```shell
-% bundle exec hanami generate app admin
-```
-
-This generates an application named `Admin` under `apps/admin`.
-
-## Actions
-
-Generate an action along with the corresponding view, template, route and test code with one command.
-
-```shell
-% bundle exec hanami generate action web books#show
-```
-
-The first argument, `web`, is the name of the target application in a Hanami project.
-
-The argument `books#show` is the name of the controller and the action separated by the number sign (`#`).
-
-If you wish to generate only the action, without the view and template, you can do that by using the `--skip-view`.
-
-```shell
-% bundle exec hanami generate action web books#show --skip-view
-```
-
-If you wish to generate action with specific method, you can do that by using the `--method`.
-
-```shell
-% bundle exec hanami generate action web books#create --method=post
-```
-
-### Route
-
-The generated route is named after the controller name.
-
-```ruby
-# apps/web/config/routes.rb
-get '/books', to: 'books#show'
-```
-
-If we want to customize the route URL, without editing our routes file, we can specify a `--url` argument.
-
-```shell
-% bundle exec hanami generate action web books#show --url=/books/:id
-```
-
-This will generate the following route:
-
-```ruby
-# apps/web/config/routes.rb
-get '/books/:id', to: 'books#show'
-```
-
-The default HTTP method is `GET`, except for actions named:
-
-- `create`, which will use `POST`
-- `update`, which will use `PATCH`
-- `destroy`, which will use `DELETE`
-
-This should help you route using [RESTful resources](/guides/1.0/routing/restful-resources).
-
-You can also set the HTTP method by specifying a `--method` argument when calling `hanami generate action`.
-
-## Models
-
-Generate an entity and a repository with a single command
-
-```shell
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create db/migrations/20170213123250_create_books.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-It generates an entity with the corresponding repository, migration, and tests.
-
-The migration will already contain the code for the creation of the table, the primary key and the timestamps:
-
-```ruby
-# db/migrations/20170213123250_create_books.rb
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-## Migrations
-
-Generate a database migration
-
-```shell
-% bundle exec hanami generate migration create_books
- create db/migrations/20161112113203_create_books.rb
-```
-
-It generates an empty migration with the UTC timestamp and the name we have specified: `db/migrations/20161112113203_create_books.rb`.
-
-## Mailers
-
-Generate a mailer
-
-```shell
-% bundle exec hanami generate mailer welcome
-```
-
-It creates the following files:
-
-```shell
-% tree lib/
-lib
-βββ bookshelf
-βΒ Β # ...
-βΒ Β βββ mailers
-βΒ Β βΒ Β βββ templates
-βΒ Β βΒ Β βΒ Β βββ welcome.html.erb
-βΒ Β βΒ Β βΒ Β βββ welcome.txt.erb
-βΒ Β βΒ Β βββ welcome.rb # Mailers::Welcome
-# ...
-```
-
-## Secret
-
-Generate a HTTP sessions secret for an application.
-
-```shell
-% bundle exec hanami generate secret web
-Set the following environment variable to provide the secret token:
-WEB_SESSIONS_SECRET="a6aa65a71538a56faffe1b1c9e96c0dc600de5dd14172f03c35cc48c3b27affe"
-```
diff --git a/source/guides/1.0/command-line/routes.md b/source/guides/1.0/command-line/routes.md
deleted file mode 100644
index 383597972..000000000
--- a/source/guides/1.0/command-line/routes.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: "Guides - Command Line: Routes"
-version: 1.0
----
-
-# Routes
-
-In order to print the routes defined by all the applications, use:
-
-```
-% bundle exec hanami routes
-
- GET, HEAD / Web::Controllers::Home::Index
- books GET, HEAD /books Web::Controllers::Books::Index
- new_books GET, HEAD /books/new Web::Controllers::Books::New
- books POST /books Web::Controllers::Books::Create
- books GET, HEAD /books/:id Web::Controllers::Books::Show
- edit_books GET, HEAD /books/:id/edit Web::Controllers::Books::Edit
- books PATCH /books/:id Web::Controllers::Books::Update
- books DELETE /books/:id Web::Controllers::Books::Destroy
- new_account GET, HEAD /account/new Web::Controllers::Account::New
- account POST /account Web::Controllers::Account::Create
- account GET, HEAD /account Web::Controllers::Account::Show
- edit_account GET, HEAD /account/edit Web::Controllers::Account::Edit
- account PATCH /account Web::Controllers::Account::Update
- account DELETE /account Web::Controllers::Account::Destroy
-```
diff --git a/source/guides/1.0/command-line/version.md.erb b/source/guides/1.0/command-line/version.md.erb
deleted file mode 100644
index da150c003..000000000
--- a/source/guides/1.0/command-line/version.md.erb
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: "Guides - Command Line: Version"
-version: 1.0
----
-
-# Version
-
-By running `hanami version` we can see the current version of the framework that we are using.
-
-```shell
-% bundle exec hanami version
-v<%= hanami_version %>
-```
-
-There are also `--version` and `-v` aliases.
-
-```shell
-% bundle exec hanami --version
-v<%= hanami_version %>
-
-% bundle exec hanami -v
-v<%= hanami_version %>
-```
diff --git a/source/guides/1.0/getting-started.md b/source/guides/1.0/getting-started.md
deleted file mode 100644
index 24c0e7901..000000000
--- a/source/guides/1.0/getting-started.md
+++ /dev/null
@@ -1,1105 +0,0 @@
----
-title: Guides - Getting Started
-version: 1.0
----
-
-# Getting Started
-
-
-
- Hello. If you're reading this page, it's very likely that you want to learn more about Hanami.
- That's great, congrats! If you're looking for new ways to build maintainable, secure, faster and testable web applications, you're in good hands.
-
-
-
- Hanami is built for people like you.
-
-
-
- I warn you that whether you're a total beginner or an experienced developer this learning process can be hard .
- Over time, we build expectations about how things should be, and it can be painful to change. But without change, there is no challenge and without challenge, there is no growth.
-
-
-
- Sometimes a feature doesn't look right, that doesn't mean it's you.
- It can be a matter of formed habits, a design fallacy or even a bug.
-
-
-
- Myself and the rest of the Community are putting best efforts to make Hanami better every day.
-
-
-
- In this guide we will set up our first Hanami project and build a simple bookshelf web application.
- We'll touch on all the major components of Hanami framework, all guided by tests.
-
-
-
- If you feel alone, or frustrated, don't give up, jump in our chat and ask for help.
- There will be someone more than happy to talk with you.
-
-
-
- Enjoy,
- Luca Guidi
- Hanami creator
-
-
-
-
-
-
-## Prerequisites
-
-Before we get started, let's get some prerequisites out of the way.
-First, we're going to assume a basic knowledge of developing web applications.
-
-You should also be familiar with [Bundler](http://bundler.io), [Rake](http://rake.rubyforge.org), working with a terminal and building apps using the [Model, View, Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) paradigm.
-
-Lastly, in this guide we'll be using a [SQLite](https://sqlite.org/) database.
-If you want to follow along, make sure you have a working installation of Ruby 2.3+ and SQLite 3+ on your system.
-
-## Create a New Hanami Project
-
-To create a new Hanami project, we need to install the Hanami gem from Rubygems.
-Then we can use the new `hanami` executable to generate a new project:
-
-```
-% gem install hanami
-% hanami new bookshelf
-```
-
-
- By default, the project will be setup to use a SQLite database. For real-world projects, you can specify your engine:
-
- % hanami new bookshelf --database=postgres
- Β
-
-
-This will create a new directory `bookshelf` in our current location.
-Let's see what it contains:
-
-```
-% cd bookshelf
-% tree -L 1
-.
-βββ Gemfile
-βββ Rakefile
-βββ apps
-βββ config
-βββ config.ru
-βββ db
-βββ lib
-βββ public
-βββ spec
-
-6 directories, 3 files
-```
-
-Here's what we need to know:
-
-* `Gemfile` defines our Rubygems dependencies (using Bundler).
-* `Rakefile` describes our Rake tasks.
-* `apps` contains one or more web applications compatible with Rack.
- Here we can find the first generated Hanami application called `Web`.
- It's the place where we find our controllers, views, routes and templates.
-* `config` contains configuration files.
-* `config.ru` is for Rack servers.
-* `db` contains our database schema and migrations.
-* `lib` contains our business logic and domain model, including entities and repositories.
-* `public` will contain compiled static assets.
-* `spec` contains our tests.
-
-Go ahead and install our gem dependency with Bundler; then we can launch a development server:
-
-```
-% bundle install
-% bundle exec hanami server
-```
-
-And... bask in the glory of your first Hanami project at
-[http://localhost:2300](http://localhost:2300)! We should see a screen similar to this:
-
-
-
-## Hanami Architecture
-
-Hanami architecture **can host several Hanami (and Rack) applications in the same Ruby process**.
-
-These applications live under `apps/`.
-Each of them can be a component of our product, such as the user facing web interface, the admin pane, metrics, HTTP API etc..
-
-All these parts are a _delivery mechanism_ to the business logic that lives under `lib/`.
-This is the place where our models are defined, and interact with each other to compose the **features** that our product provides.
-
-Hanami architecture is heavily inspired by [Clean Architecture](https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html).
-
-## Writing Our First Test
-
-The opening screen we see when we point our browser at our app, is a
-default page which is displayed when there are no routes defined.
-
-Hanami encourages [Behavior Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) (BDD) as a way to write web applications.
-In order to get our first custom page to display, we'll write a high-level feature test:
-
-```ruby
-# spec/web/features/visit_home_spec.rb
-require 'features_helper'
-
-describe 'Visit home' do
- it 'is successful' do
- visit '/'
-
- page.body.must_include('Bookshelf')
- end
-end
-```
-
-Note that, although Hanami is ready for a Behavior Driven Development workflow out of the box, **it is in no way bound to any particular testing framework** -- nor does it come with special integrations or libraries.
-
-We'll go with [Minitest](https://github.com/seattlerb/minitest) here (which is the default), but we can use [RSpec](http://rspec.info) by creating the project with `--test=rspec` option.
-Hanami will then generate helpers and stub files for it.
-
-
- Please check .env.test in case you need to tweak the database URL.
-
-
-We have to migrate our schema in the test database by running:
-
-```shell
-% HANAMI_ENV=test bundle exec hanami db prepare
-```
-
-As you can see, we have set `HANAMI_ENV` environment variable to instruct our command about the environment to use.
-
-### Following a Request
-
-Now we have a test, we can see it fail:
-
-```
-% bundle exec rake test
-Run options: --seed 44759
-
-# Running:
-
-F
-
-Finished in 0.018611s, 53.7305 runs/s, 53.7305 assertions/s.
-
- 1) Failure:
-Homepage#test_0001_is successful [/Users/hanami/bookshelf/spec/web/features/visit_home_spec.rb:6]:
-Expected "\n\n \n Not Found \n \n \n Not Found \n \n\n" to include "Bookshelf".
-
-1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
-```
-
-Now let's make it pass.
-Lets add the code required to make this test pass, step-by-step.
-
-The first thing we need to add is a route:
-
-```ruby
-# apps/web/config/routes.rb
-root to: 'home#index'
-```
-
-We pointed our application's root URL to the `index` action of the `home` controller (see the [routing guide](/guides/1.0/routing/overview) for more information).
-Now we can create the index action.
-
-```ruby
-# apps/web/controllers/home/index.rb
-module Web::Controllers::Home
- class Index
- include Web::Action
-
- def call(params)
- end
- end
-end
-```
-
-This is an empty action that doesn't implement any business logic.
-Each action has a corresponding view, which is a Ruby object and needs to be added in order to complete the request.
-
-```ruby
-# apps/web/views/home/index.rb
-module Web::Views::Home
- class Index
- include Web::View
- end
-end
-```
-
-...which, in turn, is empty and does nothing more than render its template.
-This is the file we need to edit in order to make our test pass. All we need to do is add the bookshelf heading.
-
-```erb
-# apps/web/templates/home/index.html.erb
-Bookshelf
-```
-
-Save your changes, run your test again and it now passes. Great!
-
-```shell
-Run options: --seed 19286
-
-# Running:
-
-.
-
-Finished in 0.011854s, 84.3600 runs/s, 168.7200 assertions/s.
-
-1 runs, 2 assertions, 0 failures, 0 errors, 0 skips
-```
-
-## Generating New Actions
-
-Let's use our new knowledge about the major Hanami components to add a new action.
-The purpose of our Bookshelf project is to manage books.
-
-We'll store books in our database and let the user manage them with our project.
-A first step would be to show a listing of all the books in our system.
-
-Let's write a new feature test describing what we want to achieve:
-
-```ruby
-# spec/web/features/list_books_spec.rb
-require 'features_helper'
-
-describe 'List books' do
- it 'displays each book on the page' do
- visit '/books'
-
- within '#books' do
- assert page.has_css?('.book', count: 2), 'Expected to find 2 books'
- end
- end
-end
-```
-
-The test is simple enough, and fails because the URL `/books` is not currently recognised in our application. We'll create a new controller action to fix that.
-
-### Hanami Generators
-
-Hanami ships with various **generators** to save on typing some of the code involved in adding new functionality.
-In our terminal, enter:
-
-```
-% bundle exec hanami generate action web books#index
-```
-
-This will generate a new action _index_ in the _books_ controller of the _web_ application.
-It gives us an empty action, view and template; it also adds a default route to `apps/web/config/routes.rb`:
-
-```ruby
-get '/books', to: 'books#index'
-```
-
-If you're using ZSH, you may get `zsh: no matches found: books#index`. In that case, you can use:
-```
-% hanami generate action web books/index
-```
-
-To make our test pass, we need to edit our newly generated template file in `apps/web/templates/books/index.html.erb`:
-
-```html
-Bookshelf
-All books
-
-
-
-
Patterns of Enterprise Application Architecture
-
by Martin Fowler
-
-
-
-
Test Driven Development
-
by Kent Beck
-
-
-```
-
-Save your changes and see your tests pass! The output will also contain a skipped test. This is due to an autogenerated test in `spec/web/views/books/index_spec.rb`.
-
-The terminology of controllers and actions might be confusing, so let's clear this up: actions form the basis of our Hanami applications; controllers are mere modules that group several actions together.
-So while the "controller" is _conceptually_ present in our project, in practice we only deal with actions.
-
-We've used a generator to create a new endpoint in our application.
-But one thing you may have noticed is that our new template contains the same `` as our `home/index.html.erb` template.
-Let's fix that.
-
-### Layouts
-
-To avoid repeating ourselves in every single template, we can use a layout.
-Open up the file `apps/web/templates/application.html.erb` and edit it to look like this:
-
-```rhtml
-
-
-
- Bookshelf
- <%= favicon %>
-
-
- Bookshelf
- <%= yield %>
-
-
-```
-
-Now you can remove the duplicate lines from the other templates. Let's run the tests again to check that everything worked fine:
-
-```
-bundle exec rake test
-```
-
-A **layout** is like any other template, but it is used to wrap your regular templates.
-The `yield` line is replaced with the contents of our regular template.
-It's the perfect place to put our repeating headers and footers.
-
-## Modeling Our Data With Entities
-
-Hard-coding books in our templates is, admittedly, kind of cheating.
-Let's add some dynamic data to our application.
-
-We'll store books in our database and display them on our page.
-To do so, we need a way to read and write to our database.
-Enter entities and repositories:
-
-* an **entity** is a domain object (eg. `Book`) uniquely identified by its identity.
-* a **repository** mediates between entities and the persistence layer.
-
-Entities are totally unaware of the database.
-This makes them **lightweight** and **easy to test**.
-
-For this reason we need a repository to persist the data that a `Book` depends on.
-Read more about entities and repositories in the [models guide](/guides/1.0/models/overview).
-
-Hanami ships with a generator for models, so let's use it to create a `Book` entity and the corresponding repository:
-
-```
-% bundle exec hanami generate model book
-create lib/bookshelf/entities/book.rb
-create lib/bookshelf/repositories/book_repository.rb
-create db/migrations/20161115110038_create_books.rb
-create spec/bookshelf/entities/book_spec.rb
-create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-The generator gives us an entity, a repository, a migration, and accompanying test files.
-
-### Migrations To Change Our Database Schema
-
-Let's modify the generated migration (the path to the migration will differ for you, because it contains a timestamp) to include `title` and `author` fields:
-
-```ruby
-# db/migrations/20161115110038_create_books.rb
-
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
-
- column :title, String, null: false
- column :author, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-Hanami provides a DSL to describe changes to our database schema. You can read more
-about how migrations work in the [migrations' guide](/guides/1.0/migrations/overview).
-
-In this case, we define a new table with columns for each of our entities' attributes.
-Let's prepare our database for the development and test environments:
-
-```
-% bundle exec hanami db prepare
-% HANAMI_ENV=test bundle exec hanami db prepare
-```
-
-### Working With Entities
-
-An entity is something really close to a plain Ruby object.
-We should focus on the behaviors that we want from it and only then, how to save it.
-
-For now, we keep the generated entity class:
-
-```ruby
-# lib/bookshelf/entities/book.rb
-class Book < Hanami::Entity
-end
-```
-
-This class will generate getters and setters for each attribute which we pass to initialize params.
-We can verify it all works as expected with a unit test:
-
-```ruby
-# spec/bookshelf/entities/book_spec.rb
-require_relative '../../spec_helper'
-
-describe Book do
- it 'can be initialized with attributes' do
- book = Book.new(title: 'Refactoring')
- book.title.must_equal 'Refactoring'
- end
-end
-```
-
-### Using Repositories
-
-Now we are ready to play around with our repository.
-We can use Hanami's `console` command to launch IRb with our application pre-loaded, so we can use our objects:
-
-```
-% bundle exec hanami console
->> repository = BookRepository.new
-=> => #
->> repository.all
-=> []
->> book = repository.create(title: 'TDD', author: 'Kent Beck')
-=> #1, :title=>"TDD", :author=>"Kent Beck", :created_at=>2016-11-15 11:11:38 UTC, :updated_at=>2016-11-15 11:11:38 UTC}>
->> repository.find(book.id)
-=> #1, :title=>"TDD", :author=>"Kent Beck", :created_at=>2016-11-15 11:11:38 UTC, :updated_at=>2016-11-15 11:11:38 UTC}>
-```
-
-Hanami repositories have methods to load one or more entities from our database; and to create and update existing records.
-The repository is also the place where you would define new methods to implement custom queries.
-
-To recap, we've seen how Hanami uses entities and repositories to model our data.
-Entities represent our behavior, while repositories use mappings to translate our entities to our data store.
-We can use migrations to apply changes to our database schema.
-
-### Displaying Dynamic Data
-
-With our new experience modelling data, we can get to work displaying dynamic data on our book listing page.
-Let's adjust the feature test we created earlier:
-
-```ruby
-# spec/web/features/list_books_spec.rb
-require 'features_helper'
-
-describe 'List books' do
- let(:repository) { BookRepository.new }
- before do
- repository.clear
-
- repository.create(title: 'PoEAA', author: 'Martin Fowler')
- repository.create(title: 'TDD', author: 'Kent Beck')
- end
-
- it 'displays each book on the page' do
- visit '/books'
-
- within '#books' do
- assert page.has_css?('.book', count: 2), 'Expected to find 2 books'
- end
- end
-end
-```
-
-We create the required records in our test and then assert the correct number of book classes on the page.
-When we run this test it should pass. If it does not pass, a likely reason is that the test database was not migrated.
-
-Now we can go change our template and remove the static HTML.
-Our view needs to loop over all available records and render them.
-Let's write a test to force this change in our view:
-
-```ruby
-# spec/web/views/books/index_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Views::Books::Index do
- let(:exposures) { Hash[books: []] }
- let(:template) { Hanami::View::Template.new('apps/web/templates/books/index.html.erb') }
- let(:view) { Web::Views::Books::Index.new(template, exposures) }
- let(:rendered) { view.render }
-
- it 'exposes #books' do
- view.books.must_equal exposures.fetch(:books)
- end
-
- describe 'when there are no books' do
- it 'shows a placeholder message' do
- rendered.must_include('There are no books yet.
')
- end
- end
-
- describe 'when there are books' do
- let(:book1) { Book.new(title: 'Refactoring', author: 'Martin Fowler') }
- let(:book2) { Book.new(title: 'Domain Driven Design', author: 'Eric Evans') }
- let(:exposures) { Hash[books: [book1, book2]] }
-
- it 'lists them all' do
- rendered.scan(/class="book"/).count.must_equal 2
- rendered.must_include('Refactoring')
- rendered.must_include('Domain Driven Design')
- end
-
- it 'hides the placeholder message' do
- rendered.wont_include('There are no books yet.
')
- end
- end
-end
-```
-
-We specify that our index page will show a simple placeholder message when there are no books to display; when there are, it lists every one of them.
-Note how rendering a view with some data is relatively straight-forward.
-Hanami is designed around simple objects with minimal interfaces that are easy to test in isolation, yet still work great together.
-
-Let's rewrite our template to implement these requirements:
-
-```erb
-# apps/web/templates/books/index.html.erb
-All books
-
-<% if books.any? %>
-
- <% books.each do |book| %>
-
-
<%= book.title %>
-
<%= book.author %>
-
- <% end %>
-
-<% else %>
- There are no books yet.
-<% end %>
-```
-
-If we run our feature test now, we'll see it fails β because our controller
-action does not actually [_expose_](/guides/1.0/actions/exposures) the books to our view. We can write a test for
-that change:
-
-```ruby
-# spec/web/controllers/books/index_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Controllers::Books::Index do
- let(:action) { Web::Controllers::Books::Index.new }
- let(:params) { Hash[] }
- let(:repository) { BookRepository.new }
-
- before do
- repository.clear
-
- @book = repository.create(title: 'TDD', author: 'Kent Beck')
- end
-
- it 'is successful' do
- response = action.call(params)
- response[0].must_equal 200
- end
-
- it 'exposes all books' do
- action.call(params)
- action.exposures[:books].must_equal [@book]
- end
-end
-```
-
-Writing tests for controller actions is basically two-fold: you either assert on the response object, which is a Rack-compatible array of status, headers and content; or on the action itself, which will contain exposures after we've called it.
-Now we've specified that the action exposes `:books`, we can implement our action:
-
-```ruby
-# apps/web/controllers/books/index.rb
-module Web::Controllers::Books
- class Index
- include Web::Action
-
- expose :books
-
- def call(params)
- @books = BookRepository.new.all
- end
- end
-end
-```
-
-By using the `expose` method in our action class, we can expose the contents of our `@books` instance variable to the outside world, so that Hanami can pass it to the view.
-That's enough to make all our tests pass again!
-
-```shell
-% bundle exec rake
-Run options: --seed 59133
-
-# Running:
-
-.........
-
-Finished in 0.042065s, 213.9543 runs/s, 380.3633 assertions/s.
-
-9 runs, 16 assertions, 0 failures, 0 errors, 0 skips
-```
-
-## Building Forms To Create Records
-
-One of the last remaining steps is to make it possible to add new books to the system.
-The plan is simple: we build a page with a form to enter details.
-
-When the user submits the form, we build a new entity, save it, and redirect the user back to the book listing.
-Here's that story expressed in a test:
-
-```ruby
-# spec/web/features/add_book_spec.rb
-require 'features_helper'
-
-describe 'Add a book' do
- after do
- BookRepository.new.clear
- end
-
- it 'can create a new book' do
- visit '/books/new'
-
- within 'form#book-form' do
- fill_in 'Title', with: 'New book'
- fill_in 'Author', with: 'Some author'
-
- click_button 'Create'
- end
-
- current_path.must_equal('/books')
- assert page.has_content?('New book')
- end
-end
-```
-
-### Laying The Foundations For A Form
-
-By now, we should be familiar with the working of actions, views and templates.
-
-We'll speed things up a little, so we can quickly get to the good parts.
-First, create a new action for our "New Book" page:
-
-```
-% bundle exec hanami generate action web books#new
-```
-
-This adds a new route to our app:
-
-```ruby
-# apps/web/config/routes.rb
-get '/books/new', to: 'books#new'
-```
-
-The interesting bit will be our new template, because we'll be using Hanami's form builder to construct a HTML form around our `Book` entity.
-
-### Using Form Helpers
-
-Let's use [form helpers](/guides/1.0/helpers/forms) to build this form in `apps/web/templates/books/new.html.erb`:
-
-```erb
-# apps/web/templates/books/new.html.erb
-Add book
-
-<%=
- form_for :book, '/books' do
- div class: 'input' do
- label :title
- text_field :title
- end
-
- div class: 'input' do
- label :author
- text_field :author
- end
-
- div class: 'controls' do
- submit 'Create Book'
- end
- end
-%>
-```
-
-We've added `` tags for our form fields, and wrapped each field in a
-container `` using Hanami's [HTML builder helper](/guides/1.0/helpers/html5).
-
-### Submitting Our Form
-
-To submit our form, we need yet another action.
-Let's create a `Books::Create` action:
-
-```
-% bundle exec hanami generate action web books#create
-```
-
-This adds a new route to our app:
-
-```ruby
-# apps/web/config/routes.rb
-post '/books', to: 'books#create'
-```
-
-### Implementing Create Action
-
-Our `books#create` action needs to do two things.
-Let's express them as unit tests:
-
-```ruby
-# spec/web/controllers/books/create_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Controllers::Books::Create do
- let(:action) { Web::Controllers::Books::Create.new }
- let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
- let(:repository) { BookRepository.new }
-
- before do
- repository.clear
- end
-
- it 'creates a new book' do
- action.call(params)
- book = repository.last
-
- book.id.wont_be_nil
- book.title.must_equal params.dig(:book, :title)
- end
-
- it 'redirects the user to the books listing' do
- response = action.call(params)
-
- response[0].must_equal 302
- response[1]['Location'].must_equal '/books'
- end
-end
-```
-
-Let's make these tests pass!
-We've already seen how we can write entities to our database, and we can use `redirect_to` to implement our redirection:
-
-```ruby
-# apps/web/controllers/books/create.rb
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- def call(params)
- BookRepository.new.create(params[:book])
-
- redirect_to '/books'
- end
- end
-end
-```
-
-This minimal implementation should suffice to make our tests pass.
-
-```shell
-% bundle exec rake
-Run options: --seed 63592
-
-# Running:
-
-...S.S.........
-
-Finished in 0.081961s, 183.0142 runs/s, 305.0236 assertions/s.
-
-15 runs, 23 assertions, 0 failures, 0 errors, 2 skips
-
-You have skipped tests. Run with --verbose for details.
-```
-
-Congratulations!
-
-### Securing Our Form With Validations
-
-Hold your horses! We need some extra measures to build a truly robust form.
-Imagine what would happen if the user were to submit the form without entering any values?
-
-We could fill our database with bad data or see an exception for data integrity violations.
-We clearly need a way of keeping invalid data out of our system!
-
-To express our validations in a test, we need to wonder: what _would_ happen if our validations failed?
-One option would be to re-render the `books#new` form, so we can give our users another shot at completing it correctly.
-Let's specify this behaviour as unit tests:
-
-```ruby
-# spec/web/controllers/books/create_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Controllers::Books::Create do
- let(:action) { Web::Controllers::Books::Create.new }
- let(:repository) { BookRepository.new }
-
- before do
- repository.clear
- end
-
- describe 'with valid params' do
- let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
-
- it 'creates a book' do
- action.call(params)
- book = repository.last
-
- book.id.wont_be_nil
- book.title.must_equal params.dig(:book, :title)
- end
-
- it 'redirects the user to the books listing' do
- response = action.call(params)
-
- response[0].must_equal 302
- response[1]['Location'].must_equal '/books'
- end
- end
-
- describe 'with invalid params' do
- let(:params) { Hash[book: {}] }
-
- it 'returns HTTP client error' do
- response = action.call(params)
- response[0].must_equal 422
- end
-
- it 'dumps errors in params' do
- action.call(params)
- errors = action.params.errors
-
- errors.dig(:book, :title).must_equal ['is missing']
- errors.dig(:book, :author).must_equal ['is missing']
- end
- end
-end
-```
-
-Now our tests specify two alternative scenarios: our original happy path, and a new scenario in which validations fail.
-To make our tests pass, we need to implement validations.
-
-Although you can add validation rules to the entity, Hanami also allows you to define validation rules as close to the source of the input as possible, i.e. the action.
-Hanami controller actions can use the `params` class method to define acceptable incoming parameters.
-
-This approach both whitelists what params are used (others are discarded to prevent mass-assignment vulnerabilities from untrusted user input) _and_ adds rules to define what values are acceptable β in this case we've specified that the nested attributes for a book's title and author should be present.
-
-With our validations in place, we can limit our entity creation and redirection to cases where the incoming params are valid:
-
-```ruby
-# apps/web/controllers/books/create.rb
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- expose :book
-
- params do
- required(:book).schema do
- required(:title).filled(:str?)
- required(:author).filled(:str?)
- end
- end
-
- def call(params)
- if params.valid?
- @book = BookRepository.new.create(params[:book])
-
- redirect_to '/books'
- else
- self.status = 422
- end
- end
- end
-end
-```
-
-When the params are valid, the Book is created and the action redirects to a different URL.
-But when the params are not valid, what happens?
-
-First, the HTTP status code is set to
-[422 (Unprocessable Entity)](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422).
-Then the control will pass to the corresponding view, which needs to know which template to render.
-In this case `apps/web/templates/books/new.html.erb` will be used to render the form again.
-
-```ruby
-# apps/web/views/books/create.rb
-module Web::Views::Books
- class Create
- include Web::View
- template 'books/new'
- end
-end
-```
-
-This approach will work nicely because Hanami's form builder is smart enough to inspect the `params` in this action and populate the form fields with values found in the params.
-If the user fills in only one field before submitting, they are presented with their original input, saving them the frustration of typing it again.
-
-Run your tests again and see they are all passing again!
-
-### Displaying Validation Errors
-
-Rather than just shoving the user a form under their nose when something has gone wrong, we should give them a hint of what's expected of them. Let's adapt our form to show a notice about invalid fields.
-
-First, we expect a list of errors to be included in the page when `params` contains errors:
-
-```ruby
-# spec/web/views/books/new_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Views::Books::New do
- let(:params) { OpenStruct.new(valid?: false, error_messages: ['Title must be filled', 'Author must be filled']) }
- let(:exposures) { Hash[params: params] }
- let(:template) { Hanami::View::Template.new('apps/web/templates/books/new.html.erb') }
- let(:view) { Web::Views::Books::New.new(template, exposures) }
- let(:rendered) { view.render }
-
- it 'displays list of errors when params contains errors' do
- rendered.must_include('There was a problem with your submission')
- rendered.must_include('Title must be filled')
- rendered.must_include('Author must be filled')
- end
-end
-```
-
-We should also update our feature spec to reflect this new behavior:
-
-```ruby
-# spec/web/features/add_book_spec.rb
-require 'features_helper'
-
-describe 'Add a book' do
- # Spec written earlier omitted for brevity
-
- it 'displays list of errors when params contains errors' do
- visit '/books/new'
-
- within 'form#book-form' do
- click_button 'Create'
- end
-
- current_path.must_equal('/books')
-
- assert page.has_content?('There was a problem with your submission')
- assert page.has_content?('Title must be filled')
- assert page.has_content?('Author must be filled')
- end
-end
-```
-
-In our template we can loop over `params.errors` (if there are any) and display a friendly message.
-Open up `apps/web/templates/books/new.html.erb` and add the following at the top of the file:
-
-```erb
-<% unless params.valid? %>
-
-
There was a problem with your submission
-
- <% params.error_messages.each do |message| %>
- <%= message %>
- <% end %>
-
-
-<% end %>
-```
-
-Run your tests again and see they are all passing again!
-
-```shell
-% bundle exec rake
-Run options: --seed 59940
-
-# Running:
-
-......S..........
-
-Finished in 0.188950s, 89.9707 runs/s, 179.9413 assertions/s.
-
-17 runs, 34 assertions, 0 failures, 0 errors, 1 skips
-
-You have skipped tests. Run with --verbose for details.
-```
-
-### Improving Our Use Of The Router
-
-The last improvement we are going to make, is in the use of our router.
-Open up the routes file for the "web" application:
-
-```ruby
-# apps/web/config/routes.rb
-post '/books', to: 'books#create'
-get '/books/new', to: 'books#new'
-get '/books', to: 'books#index'
-root to: 'home#index'
-```
-
-Hanami provides a convenient helper method to build these REST-style routes, that we can use to simplify our router a bit:
-
-```ruby
-root to: 'home#index'
-resources :books, only: [:index, :new, :create]
-```
-
-To get a sense of what routes are defined, now we've made this change, you can
-run `bundle exec hanami routes` on your command-line to inspect the end result:
-
-```
-% bundle exec hanami routes
- Name Method Path Action
-
- root GET, HEAD / Web::Controllers::Home::Index
- books GET, HEAD /books Web::Controllers::Books::Index
- new_book GET, HEAD /books/new Web::Controllers::Books::New
- books POST /books Web::Controllers::Books::Create
-```
-
-The output shows you the name of the defined helper method (you can suffix this name with `_path` or `_url` and call it on the `routes` helper), the allowed HTTP method, the path and finally the controller action that will be used to handle the request.
-
-Now we've applied the `resources` helper method, we can take advantage of the named route methods.
-Remember how we built our form using `form_for` in `apps/web/templates/books/new.html.erb`?
-
-```erb
-<%=
- form_for :book, '/books' do
- # ...
- end
-%>
-```
-
-We don't need to include a hard-coded path in our template, when our router is already perfectly aware of which route to point the form to.
-We can use the `routes` helper method that is available in our views and actions to access route-specific helper methods:
-
-```erb
-<%=
- form_for :book, routes.books_path do
- # ...
- end
-%>
-```
-
-We can make a similar change in `apps/web/controllers/books/create.rb`:
-
-```ruby
-redirect_to routes.books_path
-```
-
-## Wrapping Up
-
-**Congratulations for completing your first Hanami project!**
-
-Let's review what we've done: we've traced requests through Hanami's major frameworks to understand how they relate to each other; we've seen how we can model our domain using entities and repositories; we've seen solutions for building forms, maintaining our database schema, and validating user input.
-
-We've come a long way, but there's still plenty more to explore.
-Explore the [other guides](/guides), the [Hanami API documentation](http://www.rubydoc.info/gems/hanami), read the [source code](https://github.com/hanami) and follow the [blog](/blog).
-
-**Above all, enjoy building amazing things!**
-
-
-
-
- Join a community of over 2,300+ developers.
-
-
-
- By clicking "Subscribe" I want to subscribe to Hanami mailing list.
-
-
-
diff --git a/source/guides/1.0/guides.yml b/source/guides/1.0/guides.yml
deleted file mode 100644
index 4407e9f29..000000000
--- a/source/guides/1.0/guides.yml
+++ /dev/null
@@ -1,135 +0,0 @@
-categories:
- - path: /
- title: Introduction
- pages:
- - path: getting-started
- - path: architecture
- pages:
- - path: overview
- - path: projects
- pages:
- - path: code-reloading
- - path: rake
- - path: logging
- - path: initializers
- - path: security
- - path: routing
- pages:
- - path: overview
- - path: basic-usage
- - path: restful-resources
- title: RESTful Resource(s)
- - path: testing
- - path: actions
- pages:
- - path: overview
- - path: basic-usage
- - path: parameters
- - path: request-and-response
- title: Request & Response
- - path: exposures
- - path: rack-integration
- - path: mime-types
- title: MIME Types
- - path: cookies
- - path: sessions
- - path: exception-handling
- - path: control-flow
- - path: http-caching
- title: HTTP Caching
- - path: share-code
- - path: testing
- - path: views
- pages:
- - path: overview
- - path: basic-usage
- - path: templates
- - path: mime-types
- title: MIME Types
- - path: layouts
- - path: custom-error-pages
- - path: share-code
- - path: testing
- - path: models
- pages:
- - path: overview
- - path: database-configuration
- - path: repositories
- - path: entities
- - path: data-types
- - path: sql-queries
- title: SQL Queries
- - path: postgresql
- title: PostgreSQL
- - path: associations
- - path: use-your-own-orm
- title: Use Your Own ORM
- - path: migrations
- pages:
- - path: overview
- - path: create-table
- - path: alter-table
- - path: validations
- pages:
- - path: overview
- - path: boolean-logic
- - path: custom-predicates
- - path: advanced-usage
- - path: helpers
- pages:
- - path: overview
- - path: html5
- title: HTML5
- - path: forms
- - path: routing
- - path: assets
- - path: links
- - path: escape
- title: Markup Escape
- - path: numbers
- - path: custom-helpers
- - path: mailers
- pages:
- - path: overview
- - path: basic-usage
- - path: templates
- - path: delivery
- - path: share-code
- - path: testing
- - path: assets
- pages:
- - path: overview
- - path: preprocessors
- - path: compressors
- - path: content-delivery-network
- title: Content Delivery Network (CDN)
- - path: use-your-own-assets-management-tool
- title: Use Your Own Assets Management Tool
- - path: command-line
- pages:
- - path: applications
- - path: generators
- - path: destroy
- - path: database
- - path: assets
- - path: routes
- - path: version
- - path: upgrade-notes
- pages:
- - path: v060
- title: v0.6.0
- - path: v070
- title: v0.7.0
- - path: v080
- title: v0.8.0
- - path: v090
- title: v0.9.0
- - path: v100
- title: v1.0.0
- - path: /
- title: Guide Versions
- pages:
- - path: '../1.1'
- title: 'v1.1'
- - path: '1.0'
- title: v1.0
diff --git a/source/guides/1.0/helpers/assets.md b/source/guides/1.0/helpers/assets.md
deleted file mode 100644
index 083eb08fc..000000000
--- a/source/guides/1.0/helpers/assets.md
+++ /dev/null
@@ -1,419 +0,0 @@
----
-title: Guides - Assets Helpers
-version: 1.0
----
-
-## Assets Helpers
-
-These helpers are HTML5 generators that target specific assets features.
-
-They are following the settings of the application that uses them.
-For instance, if we have a project with two applications `Web` and `Admin` mounted at `/` and `/admin`, respectively, all the asset URLs will respect these prefixes.
-
-They also respect [_Fingerprint mode_](/guides/1.0/assets/overview#fingerprint-mode) and [_CDN mode_](/guides/1.0/assets/content-delivery-network) for each application.
-
-The following helpers are available for views and templates:
-
- * `javascript`
- * `stylesheet`
- * `favicon`
- * `image`
- * `video`
- * `audio`
- * `asset_path`
- * `asset_url`
-
-## Usage
-
-### `javascript`
-
-It generates a `
-
-```
-
-Alternatively, it accepts **only one** source and a Hash to represent HTML attributes.
-
-```erb
-<%= javascript 'application', async: true %>
-```
-
-```html
-
-```
-
-### `stylesheet`
-
-It generates a `
` tag for the given source(s).
-A source can be the file name without the extension, or an absolute URL.
-
-```erb
-<%= stylesheet 'reset', 'grid', 'main' %>
-```
-
-```html
-
-
-
-```
-
-Alternatively, it accepts **only one** source and a Hash to represent HTML attributes.
-
-```erb
-<%= stylesheet 'application', crossorigin: 'anonymous' %>
-```
-
-```html
-
-```
-
-### `favicon`
-
-It generates a `
` tag for the application favicon.
-
-By default it looks at `/assets/favicon.ico`.
-
-```erb
-<%= favicon %>
-```
-
-```html
-
-```
-
-We can specify a source name and HTML attributes.
-
-```erb
-<%= favicon 'favicon.png', rel: 'icon', type: 'image/png' %>
-```
-
-```html
-
-```
-
-### `image`
-
-It generates a `
` tag for the given source.
-A source can be the file name with the extension, or an absolute URL.
-
-The `alt` attribute is set automatically from file name.
-
-```erb
-<%= image 'logo.png' %>
-```
-
-```html
-
-```
-
-We can specify arbitrary HTML attributes.
-
-```erb
-<%= image 'logo.png', alt: 'Application Logo', id: 'logo', class: 'background' %>
-```
-
-```html
-
-```
-
-### `video`
-
-It generates a `
` tag for the given source.
-A source can be the file name with the extension, or an absolute URL.
-
-```erb
-<%= video 'movie.mp4' %>
-```
-
-```html
-
-```
-
-We can specify arbitrary HTML attributes.
-
-```erb
-<%= video 'movie.mp4', autoplay: true, controls: true %>
-```
-
-```html
-
-```
-
-It accepts a block for fallback message.
-
-```erb
-<%=
- video('movie.mp4') do
- "Your browser does not support the video tag"
- end
-%>
-```
-
-```html
-
- Your browser does not support the video tag
-
-```
-
-It accepts a block to specify tracks.
-
-```erb
-<%=
- video('movie.mp4') do
- track kind: 'captions', src: asset_path('movie.en.vtt'), srclang: 'en', label: 'English'
- end
-%>
-```
-
-```html
-
-
-
-```
-
-It accepts a block to specify multiple sources.
-
-```erb
-<%=
- video do
- text "Your browser does not support the video tag"
- source src: asset_path('movie.mp4'), type: 'video/mp4'
- source src: asset_path('movie.ogg'), type: 'video/ogg'
- end
-%>
-```
-
-```html
-
- Your browser does not support the video tag
-
-
-
-```
-
-### `audio`
-
-It generates a `` tag for the given source.
-A source can be the file name with the extension, or an absolute URL.
-
-```erb
-<%= audio 'song.ogg' %>
-```
-
-```html
-
-```
-
-We can specify arbitrary HTML attributes.
-
-```erb
-<%= audio 'song.ogg', autoplay: true, controls: true %>
-```
-
-```html
-
-```
-
-It accepts a block for fallback message.
-
-```erb
-<%=
- audio('song.ogg') do
- "Your browser does not support the audio tag"
- end
-%>
-```
-
-```html
-
- Your browser does not support the audio tag
-
-```
-
-It accepts a block to specify tracks.
-
-```erb
-<%=
- audio('song.ogg') do
- track kind: 'captions', src: asset_path('movie.en.vtt'), srclang: 'en', label: 'English'
- end
-%>
-```
-
-```html
-
-
-
-```
-
-It accepts a block to specify multiple sources.
-
-```erb
-<%=
- audio do
- text "Your browser does not support the audio tag"
- source src: asset_path('song.ogg'), type: 'audio/mp4'
- source src: asset_path('movie.ogg'), type: 'audio/ogg'
- end
-%>
-```
-
-```html
-
- Your browser does not support the audio tag
-
-
-
-```
-
-### `asset_path`
-
-Returns a **relative URL** for the given asset name.
-
-**This is used internally by the other helpers, so the following rules apply to all of them.**
-
-#### Asset Name
-
-When the argument is a relative name, it returns a relative URL.
-
-```erb
-<%= asset_path 'application.js' %>
-```
-
-```html
-/assets/application.js
-```
-
-#### Absolute URL
-
-When an absolute URL is given, it's **always** returned as it is, even if _Fingerprint_ or _CDN_ mode are on.
-
-```erb
-<%= asset_path 'https://code.jquery.com/jquery-2.1.1.min.js' %>
-```
-
-```html
-https://code.jquery.com/jquery-2.1.1.min.js
-```
-
-#### Fingerprint Mode
-
-When [_Fingerprint Mode_](/guides/1.0/assets/overview#fingerprint-mode) is on (usually in _production_ env), the relative URL contains a checksum suffix.
-
-```erb
-<%= asset_path 'application.css' %>
-```
-
-```html
-/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-#### CDN Mode
-
-When [_CDN Mode_](/guides/1.0/assets/content-delivery-network) is on (usually in _production_ env), it returns an absolute URL that reference the CDN settings.
-
-```erb
-<%= asset_path 'application.css' %>
-```
-
-```html
-https://123.cloudfront.net/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-
- In the example above we have a checksum suffix, because CDN vendors suggest to use this strategy while using their product.
-
-
-### `asset_url`
-
-Returns an **absolute URL** for the given asset name.
-
-To build the URL it uses `scheme`, `host`, `port` from your application settings in combination of CDN settings.
-
-#### Asset Name
-
-When the argument is a relative name, it returns an absolute URL.
-
-```erb
-<%= asset_url 'application.js' %>
-```
-
-```html
-https://bookshelf.org/assets/application.js
-```
-
-#### Absolute URL
-
-When an absolute URL is given, it's **always** returned as it is, even if _Fingerprint_ or _CDN_ mode are on.
-
-```erb
-<%= asset_url 'https://code.jquery.com/jquery-2.1.1.min.js' %>
-```
-
-```html
-https://code.jquery.com/jquery-2.1.1.min.js
-```
-
-#### Fingerprint Mode
-
-When [_Fingerprint Mode_](/guides/1.0/assets/overview#fingerprint-mode) is on (usually in _production_ env), the relative URL contains a checksum suffix.
-
-```erb
-<%= asset_url 'application.css' %>
-```
-
-```html
-https://bookshelf.org/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-#### CDN Mode
-
-When [_CDN Mode_](/guides/1.0/assets/content-delivery-network) is on (usually in _production_ env), it returns an absolute URL that reference the CDN settings.
-
-```erb
-<%= asset_url 'application.css' %>
-```
-
-```html
-https://123.cloudfront.net/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-
- In the example above we have a checksum suffix, because CDN vendors suggest to use this strategy while using their product.
-
-
-
-## Content Security Policy
-
-When using **absolute URLs as sources** or when we use a CDN, we can run into errors because our browser refute to load assets due to security restrictions (aka _"Content Security Policy"_).
-
-To fix them, we need to adjust security settings in our application.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- # If we're using our own CDN
- security.content_security_policy "default-src https://123.cloudfront.net;"
-
- # Or if we're just using jQuery public CDN
- # security.content_security_policy "default-src none; script-src 'self' https://code.jquery.com;"
- end
- end
-end
-```
-
-To learn more about Content Security Policy usage, please read:
-
- * [http://content-security-policy.com](http://content-security-policy.com)
- * [https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_Content_Security_Policy](https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_Content_Security_Policy)
diff --git a/source/guides/1.0/helpers/custom-helpers.md b/source/guides/1.0/helpers/custom-helpers.md
deleted file mode 100644
index b532a4da5..000000000
--- a/source/guides/1.0/helpers/custom-helpers.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Guides - Custom Helpers
-version: 1.0
----
-
-## Custom Helpers
-
-In the [overview](/guides/1.0/helpers/overview) section, we introduced the design for helpers.
-They are modules that enrich views behaviors.
-Because they are just Ruby modules, **we can create our own helpers**.
-
-### Example
-
-Imagine we need (for some reason) a helper that shuffles the characters of a string and we want it to be available in **all** our views.
-
-As first thing, let's define the module.
-
-```ruby
-# app/web/helpers/shuffler.rb
-module Web
- module Helpers
- module Shuffler
- private
- SEPARATOR = ''.freeze
-
- def shuffle(string)
- string
- .encode(Encoding::UTF_8, invalid: :replace)
- .split(SEPARATOR).shuffle.join
- end
- end
- end
-end
-```
-
-
- There is NO convention between the file name and the name of the module.
- We can define this code, where and how we want.
-
-
-Then let's add that directory to the load paths of the application, so it can be eagerly loaded.
-As third step, we include the module in all the views. See [View's Share Code](/guides/1.0/views/share-code) section for low level details.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- load_paths << [
- 'helpers',
- 'controllers',
- 'views'
- ]
-
- # ...
-
- view.prepare do
- include Hanami::Helpers
- include Web::Helpers::Shuffler
- end
- end
- end
-end
-```
-
-
- Please note that our custom helper will work even if we remove include Hanami::Helpers
line, because it's just Ruby.
-
diff --git a/source/guides/1.0/helpers/escape.md b/source/guides/1.0/helpers/escape.md
deleted file mode 100644
index 2c41155cf..000000000
--- a/source/guides/1.0/helpers/escape.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-title: Guides - Markup Escape Helpers
-version: 1.0
----
-
-## Markup Escape Helpers
-
-**Views escape automatically the output of their methods.**
-There are complex situations that views can't cover properly and that require an extra attention from us.
-
-Hanami makes available a set of escape helpers, to increase the security of our web applications.
-They are **public methods** that are available both in views and templates.
-
-## Escape HTML Contents
-
-It's a method called `#escape_html` (aliased as `#h`), that escapes the input.
-
-```erb
-<%= h "" %>
-```
-
-Returns
-
-```html
-<script>alert('xss')</script>
-```
-
-## Escape HTML Attributes
-
-HTML attributes are more complex to escape, because they involve attribute delimitation chars (eg. single or double quotes).
-
-We have an extra helper for this specific task: `#escape_html_attribute` (aliased as `#ha`)
-**This should be used only when the value of an attribute comes from a user input.**
-
-```erb
-
-```
-
-## Whitelisted URLs
-
-Imagine we have a feature in our application that allows users to link from their profile, a website.
-In the edit profile form we have a text field that accepts a URL.
-
-In the profile page we have a link like this:
-
-```erb
-<%= link_to "Website", user.website_url %>
-```
-
-A malicious user can edit their profile, by entering javascript code as the website URL.
-When somebody else clicks on that link, they can receive an XSS attack.
-
-Example:
-
-```html
-Website
-```
-
-The solution to this problem is to wrap the output with the `#escape_url` (aliased as `#hu`) helper.
-
-It whitelists URLs that use `http`, `https`, and `mailto` schemes, everything else is scraped.
-
-```erb
-<%= link_to "Website", hu(user.website_url) %>
-```
-
-In case we need a different set of schemes, we can specify them as second argument.
-
-```erb
-<%= link_to "Website", hu(user.website_url, ['https']) %>
-```
-
-In the code above, we're restricting to URLs that only use HTTPS.
-
-## Raw Contents
-
-There are cases when we want to print the raw contents.
-**Please be careful with this, because unescaped contents can open a breach for XSS attacks.**
-
-The helper is called `#raw`.
-
-### Specific Local
-
-If we want to escape a specific _local_:
-
-```ruby
-# apps/web/controllers/snippets/show.rb
-
-module Web::Controllers::Snippets
- class Show
- include Web::Action
-
- expose :snippet
-
- def call(params)
- @snippet = "Hello World "
- end
- end
-end
-```
-
-```ruby
-# apps/web/views/snippets/show.rb
-
-module Web::Views::Snippets
- class Show
- include Web::View
-
- def snippet
- raw locals[:snippet]
- end
- end
-end
-```
-
-```erb
-# apps/web/views/snippets/show.html.erb
-
-<%= snippet %>
-```
-
-### Entire Output
-
-We can also return unescaped output for the entire view:
-
-```ruby
-# apps/web/views/books/json_show.rb
-require 'json'
-
-module Web::Views::Books
- class JsonShow < Show
- format :json
-
- def render
- raw JSON.generate(book.to_h)
- end
- end
-end
-```
diff --git a/source/guides/1.0/helpers/forms.md b/source/guides/1.0/helpers/forms.md
deleted file mode 100644
index 043602801..000000000
--- a/source/guides/1.0/helpers/forms.md
+++ /dev/null
@@ -1,309 +0,0 @@
----
-title: Guides - Form Helpers
-version: 1.0
----
-
-## Form Helpers
-
-It provides a powerful Ruby API to describe HTML5 forms, to be used both with views and templates. It ships with:
-
- * Support for complex markup without the need of concatenation
- * Auto closing HTML5 tags
- * Support for view local variables
- * Method override support (`PUT`/`PATCH`/`DELETE` HTTP verbs aren't understood by browsers)
- * Automatic generation of HTML attributes for inputs: `id`, `name`, `value`
- * Allow to override automatic HTML attributes
- * Read values from request params and/or given entities, to autofill `value` attributes
- * Automatic selection of current value for radio button and select inputs
- * CSRF Protection
- * Infinite nested fields
- * ORM Agnostic
-
-## Technical notes
-
-This feature has a similar syntax to other Ruby gems with the same purpose, but it has a different usage if compared with Rails or Padrino.
-
-Those frameworks allow a syntax like this:
-
-```erb
-<%= form_for :book do |f| %>
-
- <%= f.text_field :title %>
-
-<% end %>
-```
-
-The code above **isn't a valid ERB template**.
-To make it work, these frameworks use custom ERB handlers and rely on third-party gems for other template engines.
-
-### Template engine independent
-
-Because we support a lot of template engines, we wanted to keep it simple: use what ERB already offers.
-That means we can use Slim, HAML, or ERB and keep the same Ruby syntax.
-
-### One output block
-
-The technical compromise for the principles described above is to use the form builder in a unique output block.
-
-```erb
-<%=
- form_for :book, routes.books_path do
- text_field :title
-
- submit 'Create'
- end
-%>
-```
-
-This will produce
-
-```html
-
-```
-
-### Method in views
-
-An **alternative usage** is to define a concrete method in a view and to use it in the template:
-
-```ruby
-module Web::Views::Books
- class New
- include Web::View
-
- def form
- form_for :book, routes.books_path do
- text_field :title
-
- submit 'Create'
- end
- end
- end
-end
-```
-
-```erb
-<%= form %>
-```
-
-### Supported methods
-
-* [check_box](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#check_box-instance_method)
-* [color_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#color_field-instance_method)
-* [datalist](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#datalist-instance_method)
-* [date_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#date_field-instance_method)
-* [datetime_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#datetime_field-instance_method)
-* [datetime\_local_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#datetime_local_field-instance_method)
-* [email_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#email_field-instance_method)
-* [fields_for](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#fields_for-instance_method)
-* [fields\_for_collection](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder:fields_for_collection)
-* [file_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#file_field-instance_method)
-* [form_for](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper#form_for-instance_method)
-* [hidden_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#hidden_field-instance_method)
-* [label](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#label-instance_method)
-* [number_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#number_field-instance_method)
-* [password_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#password_field-instance_method)
-* [radio_button](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#radio_button-instance_method)
-* [select](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#select-instance_method)
-* [submit](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#submit-instance_method)
-* [text_area](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#text_area-instance_method)
-* [text_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#text_field-instance_method)
-
-## Examples
-
-### Basic usage
-
-The API is really clean and concise, **it doesn't require concatenation** between the returning value of the block (`submit`) and the previous lines (`div`).
-
-```erb
-<%=
- form_for :book, routes.books_path, class: 'form-horizontal' do
- div do
- label :title
- text_field :title, class: 'form-control'
- end
-
- submit 'Create'
- end
-%>
-```
-
-```html
-
-```
-
-### Method override
-
-Browsers don't understand HTTP methods outside of `GET` and `POST`. On the other hand, Hanami embraces REST conventions, that goes beyond that two verbs. When we specify a method via `:method`, it adds a special hidden field `_method`, that's understood by the application.
-
-```erb
-<%=
- form_for :book, routes.book_path(book.id), method: :put do
- text_field :title
-
- submit 'Update'
- end
-%>
-```
-
-```html
-
-```
-
-### CSRF Protection
-
-Cross Site Request Forgery (CSRF) is one of the most common attacks on the web. Hanami offers a security mechanism based on a technique called: _Synchronizer Token Pattern_.
-
-When we enable sessions, it uses them to store a random token for each user.
-Forms are rendered with a special hidden field (`_csrf_token`) which contains this token.
-
-On form submission, Hanami matches this input with the value from the session. If they match, the request can continue. If not, it resets the session and raises an exception.
-
-Developers can customize attack handling.
-
-### Nested fields
-
-```erb
-<%=
- form_for :delivery, routes.deliveries_path do
- text_field :customer_name
-
- fields_for :address do
- text_field :city
- end
-
- submit 'Create'
- end
-%>
-```
-
-```html
-
-```
-
-### Nested collections
-```erb
-<%=
- form_for :delivery, routes.deliveries_path do
- text_field :customer_name
-
- fields_for_collection :addresses do
- text_field :street
- end
-
- submit 'Create'
-end
-%>
-```
-
-```html
-
-```
-
-## Automatic values
-
-Form fields are **automatically filled with the right value**. Hanami looks up for explicit values passed in the form constructor and for the params of the current request. It compares the form hierarchy (including nested fields), with these two sources. For each match, it fills the associated value.
-
-#### Example
-
-Imagine we want to update data for `delivery`. We have two objects: `delivery` and `customer`, which are plain objects (no ORM involved). They respond to the following methods:
-
-```ruby
-delivery.id # => 1
-delivery.code # => 123
-
-customer.name # => "Luca"
-
-customer.address.class # => Address
-customer.address.city # => "Rome"
-```
-
-Let's compose the form.
-
-```erb
-<%=
- form_for :delivery, routes.delivery_path(id: delivery.id), method: :patch, values: {delivery: delivery, customer: customer} do
- text_field :code
-
- fields_for :customer do
- text_field :name
-
- fields_for :address do
- text_field :city
- end
- end
-
- submit 'Update'
- end
-%>
-```
-
-```html
-
-```
-
-Please note the `:values` option that we pass to `#form_for`. It maps the `name` attributes that we have in the form with the objects that we want to use to fill the values. For instance `delivery[code]` corresponds to `delivery.code` (`123`), `delivery[customer][address][city]` to `customer.address.city` (`"Rome"`) and so on..
-
-### Read Values From Params
-
-**Params are automatically passed to form helpers**, to read values and try to autofill fields. If a value is present both in params and explicit values (`:values`), the first takes precendence. The reason is simple: params sometimes represent a failed form submission attempt.
-
-#### Example
-
-Imagine the form described above, and that our user enters `"foo"` as delivery code. This value isn't acceptable for our model domain rules, so we render again the form, presenting a validation error. Our params are now carrying on the values filled by our user. For instance: `params.get('delivery.code')` returns `"foo"`.
-
-Here how the form is rendered:
-
-```html
-
-```
diff --git a/source/guides/1.0/helpers/html5.md b/source/guides/1.0/helpers/html5.md
deleted file mode 100644
index d8a5cae1b..000000000
--- a/source/guides/1.0/helpers/html5.md
+++ /dev/null
@@ -1,221 +0,0 @@
----
-title: Guides - HTML5 Helpers
-version: 1.0
----
-
-## HTML5 Helpers
-
-This helper makes available an HTML5 generator that is **template engine independent**.
-It's a **private method for views and layouts** called `#html`.
-
-## Usage
-
-This is how it will look used with a layout:
-
-```ruby
-module Web::Views
- class ApplicationLayout
- include Web::Layout
-
- def sidebar
- html.aside(id: 'sidebar') do
- div 'hello'
- end
- end
- end
-end
-```
-
-```erb
-<%= sidebar %>
-```
-
-It generates:
-
-```html
-
-```
-
-## Features
-
- * It knows how to close tags according to HTML5 spec (1)
- * It accepts content as first argument (2)
- * It accepts builder as first argument (3)
- * It accepts content as block which returns a string (4)
- * It accepts content as a block with nested markup builders (5)
- * It builds attributes from given hash (6)
- * it combines attributes and block (7)
-
-```ruby
-# 1
-html.div # =>
-html.img # =>
-
-# 2
-html.div('hello') # => hello
-
-# 3
-html.div(html.p('hello')) # =>
-
-# 4
-html.div { 'hello' }
-# =>
-#
-# hello
-#
-
-# 5
-html.div do
- p 'hello'
-end
-# =>
-#
-
-# 6
-html.div('hello', id: 'el', 'data-x': 'y') # => hello
-
-# 7
-html.div(id: 'yay') { 'hello' }
-# =>
-#
-# hello
-#
-```
-
-It supports complex markup constructs, **without the need of concatenate tags**. In the following example, there are two `div` tags that we don't need link together.
-
-```ruby
-html.section(id: 'container') do
- div(id: 'main') do
- p 'Main content'
- end
-
- div do
- ul(id: 'languages') do
- li 'Italian'
- li 'English'
- end
- end
-end
-
-# =>
-#
-```
-
-The result is a very clean Ruby API.
-
-## Custom tags
-
-Hanami helpers support 100+ most common tags, such as `div`, `video` or `canvas`.
-However, HTML5 is fast moving target so we wanted to provide an open interface to define **new or custom tags**.
-
-The API is really simple: `#tag` must be used for a self-closing tag, where `#empty_tag` does the opposite.
-
-```ruby
-html.tag(:custom, 'Foo', id: 'next') # => Foo
-html.empty_tag(:xr, id: 'next') # =>
-```
-
-## Other helpers
-
-Hanami html helpers also support other assembled helpers. For example `link_to` helper:
-
-```ruby
-html.div do
- link_to 'hello', routes.root_path, class: 'btn'
-end
-# =>
-
-html.div do
- link_to 'Users', routes.users_path, class: 'btn'
- hr
- link_to 'Books', routes.books_path, class: 'btn'
-end
-
-# =>
-```
-
-## Auto escape
-
-The tag contents are automatically escaped for **security** reasons:
-
-```ruby
-html.div('hello') # => hello
-html.div { 'hello' } # => hello
-html.div(html.p('hello')) # =>
-html.div do
- p 'hello'
-end # =>
-
-
-
-html.div("")
- # => "<script>alert('xss')</script>
"
-
-html.div { "" }
- # => "<script>alert('xss')</script>
"
-
-html.div(html.p(""))
- # => "<script>alert('xss')</script>
"
-
-html.div do
- p ""
-end
- # => "<script>alert('xss')</script>
"
-```
-
-**HTML attributes aren't automatically escaped**, in case we need to use a value that comes from a user input, we suggest to use `#ha`, which is the escape helper designed for this case. See [Escape Helpers](/guides/1.0/helpers/escape) for a deep explanation.
-
-## View Context
-
-Local variables from views are available inside the nested blocks of HTML builder:
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def title_widget
- html.div do
- h1 book.title
- end
- end
- end
-end
-```
-
-```erb
-
- <%= title_widget %>
-
-```
-
-```html
-
-
-
The Work of Art in the Age of Mechanical Reproduction
-
-
-```
-
diff --git a/source/guides/1.0/helpers/links.md b/source/guides/1.0/helpers/links.md
deleted file mode 100644
index 07ec9d33d..000000000
--- a/source/guides/1.0/helpers/links.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Guides - Link Helpers
-version: 1.0
----
-
-## Link Helpers
-
-It provides a concise API to generate links.
-It's a **public method** called `#link_to`, that can be used both in **views** and **templates**.
-
-## Usage
-
-It accepts two mandatory and one optional arguments.
-The first is the content of the tag, the second is the path, an the third is a Hash that represents a set of HTML attributes that we may want to specify.
-
-```erb
-<%= link_to 'Home', '/' %>
-<%= link_to 'Profile', routes.profile_path, class: 'btn', title: 'Your profile' %>
-<%=
- link_to(routes.profile_path, class: 'avatar', title: 'Your profile') do
- img(src: user.avatar.url)
- end
-%>
-```
-
-Output:
-
-```html
-Home
-Profile
-
-
-
-```
-
-Alternatively, the content can be expressed as a given block.
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def look_inside_link
- url = routes.look_inside_book_path(id: book.id)
-
- link_to url, class: 'book-cover' do
- html.img(src: book.cover_url)
- end
- end
- end
-end
-```
-
-Template:
-
-```erb
-<%= look_inside_link %>
-```
-
-Output:
-
-```html
-
-
-
-```
-
-## Security
-
-There are two aspects to consider when we use links in our markup: **whitelisted URLs** and **escaped attributes**.
-Please visit the [Markup Escape](/guides/1.0/helpers/escape) section for a detailed explanation.
diff --git a/source/guides/1.0/helpers/numbers.md b/source/guides/1.0/helpers/numbers.md
deleted file mode 100644
index a93ffe9f9..000000000
--- a/source/guides/1.0/helpers/numbers.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Guides - Number Helpers
-version: 1.0
----
-
-## Number Helpers
-
-Hanami offers a helpful way to present numbers via `#format_number`, a **private method** available only in views.
-
-## Usage
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def download_count
- format_number book.download_count
- end
- end
-end
-```
-
-```erb
-<%= download_count %>
-```
-
-```html
-1,000,000
-```
-
-### Precision
-
-The default precision is of `2`, but we can specify a different value with the homonym option.
-
-```ruby
-format_number(Math::PI) # => "3.14"
-format_number(Math::PI, precision: 6) # => "3.141592"
-```
-
-### Delimiter
-
-The default thousands delimiter is `,`. We can use `:delimiter` for a different char.
-
-```ruby
-format_number(1_000_000) # => "1,000,000"
-format_number(1_000_000, delimiter: '.') # => "1.000.000"
-```
-
-### Separator
-
-The default separator is `.`. We can use `:separator` for a different char.
-
-```ruby
-format_number(1.23) # => "1.23"
-format_number(1.23, separator: ',') # => "1,23"
-```
diff --git a/source/guides/1.0/helpers/overview.md b/source/guides/1.0/helpers/overview.md
deleted file mode 100644
index afc85dcff..000000000
--- a/source/guides/1.0/helpers/overview.md
+++ /dev/null
@@ -1,133 +0,0 @@
----
-title: Guides - Helpers Overview
-version: 1.0
----
-
-# Overview
-
-A Hanami view is an object that defines presentational logic.
-Helpers are modules designed to enrich views with a collection of useful features.
-
-This concept is probably familiar, if you know some Ruby basics.
-
-```ruby
-module Printable
- def print
- puts "..."
- end
-end
-
-class Person
- include Printable
-end
-
-Person.new.print
-```
-
-The same simple design is applied to views and helpers.
-
-Hanami ships with default helpers, but we can also define custom helper modules.
-
-## Rendering Context
-
-Views are Ruby objects that are responsible for rendering the associated template.
-The context for this activity is defined only by the set of methods that a view can respond to.
-
-If a view has a method `#greeting`, we can use it like this: `<%= greeting %>`.
-
-This design has a few important advantages:
-
- * It facilitates debugging. In the case of an exception, we know that **the view is the only rendering context to inspect**.
- * Ruby method dispatcher will be **fast**, as it doesn't need to do a lookup for many method sources.
-
-Consider the following code:
-
-```ruby
-# apps/web/views/books/show.rb
-module Web::Views::Books
- include Web::View
-
- def home_page_link
- link_to "Home", "/"
- end
-end
-```
-
-Our view responds to `#link_to`, because it includes `Hanami::Helpers::LinkToHelper`, a module that defines that concrete method.
-
-## Clean Context
-
-There are some helpers that have a huge interface.
-Think of the [HTML5](/guides/1.0/helpers/html5) or the [routing](/guides/1.0/helpers/routing) helpers, they provide hundreds of methods to map tags or application routes.
-
-Making them available directly in the view context, would be source of confusion, slow method dispatch times and name collisions.
-
-Imagine we have an application with 100 routes.
-Because Hanami provides both relative and absolute URI facilities, if used directly, it would mean adding **200 methods** to all the views.
-Which is overkill.
-
-For this reason, certain helpers act as a proxy to access these large set of methods.
-
-```erb
-<%= routes.home_path %>
-```
-
-In this case we have **only one method** to add to our views, but it opens an infinite number of possibilities without causing performance issues.
-
-## Explicit Interfaces
-
-Hanami guides developers to design explicit and intention revealing interfaces for their objects.
-Almost all the default helpers, make **private methods** available to our views.
-
-We want to avoid complex expressions that will clutter our templates, and make sure that views remain testable.
-
-Here an example of **poor** and **untestable** code in a template.
-
-```erb
-<%= format_number book.downloads_count %>
-```
-
-If we want to unit test this logic, we can't do it directly, unless we render the template and match the output.
-
-For this reason `#format_number`, is shipped as a private method, so we are forced to define an explicit method for our interface.
-
-```ruby
-# apps/web/views/books/show.rb
-module Web::Views::Books
- include Web::View
-
- def downloads_count
- format_number book.downloads_count
- end
-end
-```
-
-To be used like this:
-
-```erb
-<%= downloads_count %>
-```
-
-This version is **visually simpler** and **testable**.
-
-## Disable Helpers
-
-Helpers aren't mandatory for Hanami applications.
-If we want to get rid of them, we just to need to remove two lines of code.
-
-```ruby
-# apps/web/application.rb
-require 'hanami/helpers' # REMOVE THIS LINE
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- view.prepare do
- include Hanami::Helpers # AND THIS ONE
- end
- end
- end
-end
-```
diff --git a/source/guides/1.0/helpers/routing.md b/source/guides/1.0/helpers/routing.md
deleted file mode 100644
index 753a56b04..000000000
--- a/source/guides/1.0/helpers/routing.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: Guides - Routing Helpers
-version: 1.0
----
-
-## Routing Helpers
-
-Routing helpers are made of one **public method** (`#routes`), available for actions, views and templates.
-It's a factory to generate **relative** or **absolute URLs**, starting from [named routes](/guides/1.0/routing/basic-usage).
-
-
- For a given route named :home
, we can use home_path
or home_url
to generate relative or absolute URLs, respectively.
-
-
-## Usage
-
-Imagine we have the following routes for our application:
-
-```ruby
-# apps/web/config/routes.rb
-root to: 'home#index'
-get '/foo', to: 'foo#index'
-
-resources :books
-```
-
-### Relative URLs
-
-We can do:
-
-```erb
-
-```
-
-Which generates:
-
-```html
-
-```
-
-We can't link `/foo`, because it isn't a named route (it lacks of the `:as` option).
-
-### Absolute URLs
-
-```ruby
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- def call(params)
- # ...
- redirect_to routes.book_url(id: book.id)
- end
- end
-end
-```
-
-In the case above, we have passed a Hash as set of params that are required to generate the URL.
-
-
- Absolute URL generation is dependent on scheme
, host
and port
settings in apps/web/application.rb
.
-
diff --git a/source/guides/1.0/index.md b/source/guides/1.0/index.md
deleted file mode 100644
index a80d95ed9..000000000
--- a/source/guides/1.0/index.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: Guides
-version: 1.0
----
-
-# Introduction
-
-## What is Hanami?
-
-Hanami is a Ruby MVC web framework comprised of many micro-libraries.
-It has a simple, stable API, a minimal DSL, and prioritises the use of plain objects over magical, over-complicated classes with too much responsibility.
-
-The natural repercussion of using simple objects with clear responsibilities is more boilerplate code.
-Hanami provides ways to mitigate this extra legwork while maintaining the underlying implementation.
-
-## Why Choose Hanami?
-
-Here are three compelling reasons to choose Hanami:
-
-### Hanami is Lightweight
-
-Hanami's code is relatively short.
-It only concerns itself with the things that all web applications—regardless of implementation—need.
-
-Hanami ships with several optional modules and other libraries can also be included easily.
-
-### Hanami is Architecturally Sound
-
-If you've ever felt you're stretching against the "Rails way", you'll appreciate Hanami.
-
-Hanami keeps controller actions class-based, making them easier to test in isolation.
-
-Hanami also encourages you to write your application logic in use cases objects (aka _interactors_).
-
-Views are separated from templates so the logic inside can be well-contained and tested in isolation.
-
-### Hanami is Threadsafe
-
-Making use of threads is a great way to boost the performance of your
-application. It shouldn't be hard to write thread-safe code, and Hanami (whether
-the entire framework, or parts of it) is runtime threadsafe.
-
-## Guides
-
-The guides explain high level Hanami components and how to configure, use and test them in a full stack application.
-The imaginary product that we'll mention is called _"Bookshelf"_: a online community to share readings and buy books.
-
-We have a [getting started guide](/guides/1.0/getting-started), to build our first application with Hanami.
diff --git a/source/guides/1.0/mailers/basic-usage.md b/source/guides/1.0/mailers/basic-usage.md
deleted file mode 100644
index 3d8de021e..000000000
--- a/source/guides/1.0/mailers/basic-usage.md
+++ /dev/null
@@ -1,107 +0,0 @@
----
-title: Guides - Mailers Basic Usage
-version: 1.0
----
-
-# Basic Usage
-
-In the [previous section](/guides/1.0/mailers/overview), we generated a mailer, let's use it.
-
-## Information
-
-Firstly, we need to specify sender and recipient(s) and the subject of the email.
-For this purpose a mailer exposes three mandatory methods: `.from`, `.to`, `.subject` and two optional: `.cc`, `.bcc`.
-
-They all accept a string, but `.to` can also accept an array of strings in order to set multiple recipients.
-
-```ruby
-class Mailers::Welcome
- include Hanami::Mailer
-
- from 'noreply@bookshelf.org'
- to 'user@example.com'
- subject 'Welcome to Bookshelf'
-end
-```
-
-
- Both .from
and .to
MUST be specified when we deliver an email.
-
-
-
- An email subject isn't mandatory, but it's a good practice to set this information.
-
-
-You may have noticed that have a hardcoded value can be useful to set the sender, but it doesn't work well for the rest of the details.
-
-If you pass a **symbol as an argument**, it will be interpreted as a **method** that we want to use for that information.
-
-
-```ruby
-class Mailers::Welcome
- include Hanami::Mailer
-
- from 'noreply@bookshelf.org'
- to :recipient
- subject :subject
-
- private
-
- def recipient
- user.email
- end
-
- def subject
- "Welcome #{ user.name }!"
- end
-end
-```
-
-
- There is NOT a convention between the name of the methods and their corresponding DSL.
-
-
-
- We suggest to use always private methods for these informations, unless they need to be available from the templates.
-
-
-## Context
-
-### Locals
-
-In the previous section, we have referenced an `user` variable, where does it come from?
-Similarly to a [view](/guides/1.0/views/basic-usage), a mailer can have a set of _locals_ that can be passed as an argument in order to make them available during the rendering.
-
-```ruby
-u = User.new(name: 'Luca', email: 'luca@example.com')
-Mailers::Welcome.deliver(user: u)
-```
-
-We can specify as many locals as we want, the key that we use for each of them it's the same that we use to reference that object.
-For instance, we passed `:user` key, and we can use `user` in the mailer and its associated templates.
-
-
- The following keys for locals are RESERVED: :format
and :charset
.
-
-
-### Scope
-
-All the public methods defined in a mailer are accessible from the templates:
-
-```ruby
-# lib/bookshelf/mailers/welcome.rb
-class Mailers::Welcome
- include Hanami::Mailer
-
- # ...
-
- def greeting
- "Ahoy"
- end
-end
-```
-
-```erb
-# lib/bookshelf/mailers/templates/welcome.html.erb
-<%= greeting %>
-```
diff --git a/source/guides/1.0/mailers/delivery.md b/source/guides/1.0/mailers/delivery.md
deleted file mode 100644
index 585cb8569..000000000
--- a/source/guides/1.0/mailers/delivery.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-title: Guides - Mailers Delivery
-version: 1.0
----
-
-# Delivery
-
-## Multipart Delivery
-
-By default a mailer delivers a multipart email, that has a HTML and a text part.
-This is the reason why the generator creates two templates.
-
-To render both the templates and deliver them as a multipart message, we simply do:
-
-```ruby
-Mailers::Welcome.deliver
-```
-
-Hanami mailers are flexible enough to adapt to several scenarios.
-
-## Single Part Delivery
-
-Let's say in our application users can opt for HTML or textual emails.
-According to this configuration, we want to selectively send only the wanted format:
-
-```ruby
-Mailers::Welcome.deliver(format: :html)
-# or
-Mailers::Welcome.deliver(format: :txt)
-```
-
-By using only one format, it will render and deliver only the specified template.
-
-## Remove Templates
-
-If in our application, we want only to deliver HTML templates, we can **safely** remove textual templates (`.txt` extension) and every time we will do `Mailers::Welcome.deliver` it will only send the HTML message.
-
-The same principle applies if we want only to send textual emails, just remove HTML templates (`.html` extension).
-
-
- At the delivery time, a mailer MUST have at least one template available.
-
-
-## Configuration
-
-In order to specify the gateway to use for our email messages, we can use `delivery` configuration.
-
-### Built-in Methods
-
-It accepts a symbol that is translated into a delivery strategy:
-
- * Exim (`:exim`)
- * Sendmail (`:sendmail`)
- * SMTP (`:smtp`, for local SMTP installations)
- * SMTP Connection (`:smtp_connection`, via `Net::SMTP` - for remote SMTP installations)
- * Test (`:test`, for testing purposes)
-
-It defaults to SMTP (`:smtp`) for production environment, while `:test` is automatically set for development and test.
-
-The second optional argument is a set of arbitrary configurations that we want to pass to the configuration:
-
-```ruby
-# config/environment.rb
-# ...
-Hanami.configure do
- # ...
-
- mailer do
- root Hanami.root.join("lib", "bookshelf", "mailers")
-
- # See http://hanamirb.org/guides/mailers/delivery
- delivery :test
- end
-
- # ...
-
- environment :production do
- # ...
-
- mailer do
- delivery :smtp, address: ENV['SMTP_HOST'], port: ENV['SMTP_PORT']
- end
- end
-end
-```
-
-For advanced configurations, please have a look at `mail` [gem](https://github.com/mikel/mail) by Mikel Lindsaar.
-At the low level, **Hanami::Mailer** uses this rock solid library.
-
-Because Hanami uses `mail` gem, which is a _de facto_ standard for Ruby, we can have interoperability with all the most common gateways vendors.
-[Sendgrid](https://devcenter.heroku.com/articles/sendgrid#ruby-rails), [Mandrill](https://devcenter.heroku.com/articles/mandrill#sending-with-smtp), [Postmark](https://devcenter.heroku.com/articles/postmark#sending-emails-via-the-postmark-smtp-interface) and [Mailgun](https://devcenter.heroku.com/articles/mailgun#sending-emails-via-smtp) just to name a few, use SMTP and have detailed setup guides.
-
-### Custom Methods
-
-If we need to a custom delivery workflow, we can pass a class to the configuration.
-
-Here's an example on how to use [Mandrill API](https://mandrillapp.com/api/docs/) to deliver emails.
-
-```ruby
-# config/environment.rb
-# ...
-require 'lib/mailers/mandrill_delivery_method'
-
-Hanami.configure do
- # ...
-
- environment :production do
- # ...
-
- mailer do
- production MandrillDeliveryMethod, api_key: ENV['MANDRILL_API_KEY']
- end
- end
-end
-```
-
-The object MUST respond to `#initialize(options = {})` and to `#deliver!(mail)`, where `mail` is an instance of [`Mail::Message`](https://github.com/mikel/mail/blob/master/lib/mail/mail.rb).
-
-```ruby
-class MandrillDeliveryMethod
- def initialize(options)
- @api_key = options.fetch(:api_key)
- end
-
- def deliver!(mail)
- send convert(mail)
- end
-
- private
-
- def send(message)
- gateway.messages.send message
- end
-
- def convert(mail)
- # Convert a Mail::Message instance into a Hash structure
- # See https://mandrillapp.com/api/docs/messages.ruby.html
- end
-
- def gateway
- Mandrill::API.new(@api_key)
- end
-end
-```
-
-
- Please notice that this is only an example that illustrates custom policies. If you want to use Mandrill, please prefer SMTP over this strategy.
-
diff --git a/source/guides/1.0/mailers/overview.md b/source/guides/1.0/mailers/overview.md
deleted file mode 100644
index 0171780cd..000000000
--- a/source/guides/1.0/mailers/overview.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Guides - Mailers Overview
-version: 1.0
----
-
-# Overview
-
-A mailer is an object that's responsible to deliver a mail message, by rendering one or more templates.
-
-For simplicity, each mailer can handle **only one use case (feature)**.
-If in our application we need to send emails for several features like: _"confirm your email address"_ or _"forgot password"_, we will have `Mailers::ConfirmEmailAddress` and `Mailers::ForgotPassword` **instead** of a generic `UserMailer` that manages all these use cases.
-
-## A Simple Mailer
-
-Hanami ships a generator that creates a mailer, two templates and the test code.
-
-```shell
-% hanami generate mailer welcome
- create spec/bookshelf/mailers/welcome_spec.rb
- create lib/bookshelf/mailers/welcome.rb
- create lib/bookshelf/mailers/templates/welcome.html.erb
- create lib/bookshelf/mailers/templates/welcome.txt.erb
-```
-
-Let's see how a mailer is structured:
-
-```ruby
-# lib/bookshelf/mailers/welcome.rb
-class Mailers::Welcome
- include Hanami::Mailer
-end
-```
-
-
- All the mailers are available under the Mailers
namespace.
-
-
diff --git a/source/guides/1.0/mailers/share-code.md b/source/guides/1.0/mailers/share-code.md
deleted file mode 100644
index 6ec6a011b..000000000
--- a/source/guides/1.0/mailers/share-code.md
+++ /dev/null
@@ -1,54 +0,0 @@
----
-title: Guides - Mailes Share Code
-version: 1.0
----
-
-# Share Code
-
-## Prepare
-
-In our settings (`lib/bookshelf.rb`), there is code block that allows to share the code for **all the mailers** of our application.
-When a mailer includes the `Hanami::Mailer` module, that block code is yielded within the context of that class.
-This is heavily inspired by Ruby Module and its `included` hook.
-
-Imagine we want to set a default sender for all the mailers.
-Instead of specifying it for each mailer, we can use a DRY approach.
-
-We create a module:
-
-```ruby
-# lib/mailers/default_sender.rb
-module Mailers::DefaultSender
- def self.included(mailer)
- mailer.class_eval do
- from 'sender@bookshelf.org'
- end
- end
-end
-```
-
-Then we include in all the mailers of our application, via `prepare`.
-
-```ruby
-# lib/bookshelf.rb
-# ...
-
-Hanami.configure do
- # ...
- mailer do
- root 'lib/bookshelf/mailers'
-
- # See http://hanamirb.org/guides/mailers/delivery
- delivery :test
-
- prepare do
- include Mailers::DefaultSender
- end
- end
-end
-```
-
-
-Code included via prepare
is available for ALL the mailers of an application.
-
-
diff --git a/source/guides/1.0/mailers/templates.md b/source/guides/1.0/mailers/templates.md
deleted file mode 100644
index ba1ca1db6..000000000
--- a/source/guides/1.0/mailers/templates.md
+++ /dev/null
@@ -1,191 +0,0 @@
----
-title: Guides - View Templates
-version: 1.0
----
-
-# Templates
-
-A template is a file that contains a body for a specific format of a multipart email.
-For instance, `welcome.html.erb` describes the markup of the HTML part of the message, while `welcome.txt.erb` is for the textual part.
-
-It is rendered by bounding the [context](/guides/1.0/mailers/basic-usage) of a mailer and using a _template engine_.
-
-## Naming
-
-For convenience, there is a correlation between the view mailer name and the template file name.
-It's the translation of the name into a path: from `Mailers::ForgotPassword` to `forgot_password`.
-
-The remaining part is made of multiple file extensions.
-The first is relative to the **_format_** and the latter is for the **_template engine_**.
-
-**Hanami only accepts `html` and `txt` formats for emails.**
-
-
-For a given mailer named Mailers::ForgotPassword
, there must be at least one template forgot_password.[format].[engine]
under the mailers templates directory.
-
-
-### Custom Template
-
-If we want to associate a different template to a mailer, we can use `template`.
-
-```ruby
-# lib/bookshelf/mailers/forgot_password.rb
-class Mailers::ForgotPassword
- include Hanami::Mailer
- template 'send_password'
-end
-```
-
-Our view will look for `lib/bookshelf/mailers/templates/send_password.*` template.
-
-## Engines
-
-Hanami looks at the last extension of a template file name to decide which engine to use (eg `welcome.html.erb` will use ERb).
-The builtin rendering engine is [ERb](http://en.wikipedia.org/wiki/ERuby), but Hanami supports countless rendering engines out of the box.
-
-This is a list of the supported engines.
-They are listed in order of **higher precedence**, for a given extension.
-For instance, if [ERubis](http://www.kuwata-lab.com/erubis/) is loaded, it will be preferred over ERb to render `.erb` templates.
-
-
-
- Engine
- Extensions
-
-
- Erubis
- erb, rhtml, erubis
-
-
- ERb
- erb, rhtml
-
-
- Redcarpet
- markdown, mkd, md
-
-
- RDiscount
- markdown, mkd, md
-
-
- Kramdown
- markdown, mkd, md
-
-
- Maruku
- markdown, mkd, md
-
-
- BlueCloth
- markdown, mkd, md
-
-
- Asciidoctor
- ad, adoc, asciidoc
-
-
- Builder
- builder
-
-
- CSV
- rcsv
-
-
- CoffeeScript
- coffee
-
-
- WikiCloth
- wiki, mediawiki, mw
-
-
- Creole
- wiki, creole
-
-
- Etanni
- etn, etanni
-
-
- Haml
- haml
-
-
- Less
- less
-
-
- Liquid
- liquid
-
-
- Markaby
- mab
-
-
- Nokogiri
- nokogiri
-
-
- Plain
- html
-
-
- RDoc
- rdoc
-
-
- Radius
- radius
-
-
- RedCloth
- textile
-
-
- Sass
- sass
-
-
- Scss
- scss
-
-
- Slim
- slim
-
-
- String
- str
-
-
- Yajl
- yajl
-
-
-
-In order to use a different template engine we need to bundle the gem and to use the right file extension.
-
-```haml
-# lib/bookshelf/mailers/templates/welcome.html.haml
-%h1 Welcome
-```
-
-## Templates Directory
-
-Templates are located in the default directory `mailers/templates`, located under an application's directory `lib/bookshelf`, where `bookshelf` is the name of our application.
-If we want to customize this location, we can set a different value in Hanami::Mailer configuration.
-
-```ruby
-# lib/bookshelf.rb
-# ...
-
-Hanami::Mailer.configure do
- # ...
- root 'path/to/templates'
-end.load!
-```
-
-The application will now look for templates under `path/to/templates`.
diff --git a/source/guides/1.0/mailers/testing.md b/source/guides/1.0/mailers/testing.md
deleted file mode 100644
index ffa2d7675..000000000
--- a/source/guides/1.0/mailers/testing.md
+++ /dev/null
@@ -1,34 +0,0 @@
----
-title: Guides - Mailers Testing
-version: 1.0
----
-
-# Testing
-
-During development and testing we don't want to accidentally send emails to the real world.
-The [delivery method](/guides/1.0/mailers/delivery) for these two envs is set to `:test`.
-
-In order to assert that a mailer sent a message, we can look at `Hanami::Mailer.deliveries`.
-It's an array of messages that the framework pretended to deliver during a test.
-Please make sure to **clear** them in testing setup.
-
-```ruby
-# spec/bookshelf/mailers/welcome_spec.rb
-require 'spec_helper'
-
-describe Mailers::Welcome do
- before do
- Hanami::Mailer.deliveries.clear
- end
-
- let(:user) { ... }
-
- it "delivers welcome email" do
- Mailers::Welcome.deliver(user: user)
- mail = Hanami::Mailer.deliveries.last
-
- mail.to.must_equal [user.email]
- mail.body.encoded.must_include "Hello, #{ user.name }"
- end
-end
-```
diff --git a/source/guides/1.0/migrations/alter-table.md b/source/guides/1.0/migrations/alter-table.md
deleted file mode 100644
index d9399385e..000000000
--- a/source/guides/1.0/migrations/alter-table.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Guides - Migrations Alter Tables
-version: 1.0
----
-
-# Alter Tables
-
-The following methods are available for table alterations:
-
- * `#add_column` (see `#column` for usage)
- * `#drop_column`
- * `#rename_column` (the first argument is the **old name**, while the second is the **new name**)
- * `#add_index` (see `#index` for usage)
- * `#drop_index`
- * `#add_primary_key` (see `#primary_key` for usage)
- * `#add_foreign_key` (see `#foreign_key` for usage)
- * `#add_constraint` (see `#constraint` for usage)
- * `#drop_constraint` (accepts the **name** of the constraint as argument)
- * `#add_unique_constraint`
- * `#set_column_default` (accepts the **name** of the column and the **default value** as comma separated args)
- * `#set_column_type` (accepts the **name** of the column and the **new type** as comma separated args)
- * `#set_column_allow_null` (accepts the **name** of the column)
- * `#set_column_not_null` (accepts the **name** of the column)
-
-Those methods accept the **name of the target table as first argument**, then the other args.
-There is a convenient shortcut for this: `#alter_table`. It accepts the **name of the table** and a **block** that describes the alterations.
-
-The following syntaxes are **equivalent**.
-
-```ruby
-Hanami::Model.migration do
- change do
- add_column :users, :email, String, null: false, unique: true
- set_column_default :users, :visits_counts, default: 0
- end
-end
-```
-
-The code above can be DRY'd with:
-
-```ruby
-Hanami::Model.migration do
- change do
- alter_table :users do
- # `users` table is implicit within this block, so it can be omitted.
- add_column :email, String, null: false, unique: true
- set_column_default :visits_counts, default: 0
- end
- end
-end
-```
-
-## Rename Table
-
-Tables can be renamed via `#rename_table`. It accepts the **old name** and the **new name** as arguments.
-
-```ruby
-rename_table :users, :people
-```
-
-## Drop Table
-
-Tables can be dropped via `#drop_table`. It accepts the **name** as argument.
-
-```ruby
-drop_table :users
-```
-
-Safe operation can be performed via `#drop_table?`. It drops the table only if it exists.
diff --git a/source/guides/1.0/migrations/create-table.md b/source/guides/1.0/migrations/create-table.md
deleted file mode 100644
index da0b5ea9b..000000000
--- a/source/guides/1.0/migrations/create-table.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: Guides - Migrations Create Tables
-version: 1.0
----
-
-# Create Tables
-
-A table is defined via `#create_table`. This method accepts two arguments: the **name** and a **block** that expresses the design.
-
-Safe operation can be performed via `#create_table?`. It only creates the table if it doesn't exist.
-Force operation can be performed via `#create_table!`. It drops the existing table and creates a new one from scratch.
-**These operations shouldn't be used in migrations**.
-
-## Column Definition
-
-To define a column we use `#column`, followed by the **name**, the **type** and **options**.
-The name must be a unique identifier within the table.
-
-The type can be a Ruby type (e.g. `String`), a symbol that represents a Ruby type (e.g. `:string`), or a string that represents the raw database type (e.g. `"varchar(255)"`). The only one exception in case of symbol is :Bignum. Using the symbol :Bignum as a type will use the appropriate 64-bit integer type for the database you are using.
-
-## Type Definition
-
-The following Ruby types are supported:
-
- * `String` (`varchar(255)`)
- * `Numeric` (`numeric`)
- * `Fixnum` (`integer`)
- * `Integer` (`integer`)
- * `:Bignum` (`bigint`) # Note: use this type as a symbol, since Ruby 2.4.0 removed Bignum class
- * `Float` (`double precision`)
- * `BigDecimal` (`numeric`)
- * `Date` (`date`)
- * `DateTime` (`timestamp`)
- * `Time` (`timestamp`)
- * `TrueClass` (`boolean`)
- * `FalseClass` (`boolean`)
- * `File` (`blob`)
-
-Their translation from Ruby types to database types may vary from database to database.
-
-### Options
-
-It supports the following options:
-
- * `:default` (default value)
- * `:index` (create an index for the column)
- * `:null` (allow NULL values or not)
- * `:primary_key` (make the column primary key for the table)
- * `:unique` (add a uniqueness constraint for the column)
-
-
- Note that Hanami natively supports PostgreSQL data types .
- Learn more about them in the dedicated article .
-
-
-## Primary Key
-
-We can define **primary keys** with the following syntaxes:
-
-```ruby
-column :id, Integer, null: false, primary_key: true
-# or just use this shortcut
-primary_key :id
-```
-
-## Foreign Keys
-
-**Foreign keys** are defined via `#foreign_key`, where we specify the **name** of the column, the **referenced table**, and a set of **options**.
-The following example creates an `author_id` column (integer) for `books` and adds a foreign key.
-
-```ruby
-create_table :books do
- # ...
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-end
-```
-
-### Options
-
-It accepts the following options:
-
- * `:deferrable` (make the constraint check deferrable at the end of a transaction)
- * `:key` (the column in the associated table that this column references. Unnecessary if this column references the primary key of the associated table)
- * `:null` (allow NULL values or not)
- * `:type` (the column type)
- * `:on_delete` (action to take if the referenced record is deleted: `:restrict`, `:cascade`, `:set_null`, or `:set_default`)
- * `:on_update` (action to take if the referenced record is updated: `:restrict`, `:cascade`, `:set_null`, or `:set_default`)
-
-
-## Indexes
-
-Indexes are defined via `#index`. It accepts the **name(s)** of the column(s), and a set of **options**.
-
-```ruby
-create_table :stores do
- # ...
- column :code, Integer, null: false
- column :lat, Float
- column :lng, Float
-
- index :code, unique: true
- index [:lat, :lng], name: :stores_coords_index
-end
-```
-
-### Options
-
-It accepts the following options:
-
- * `:unique` (uniqueness constraint)
- * `:name` (custom name)
- * `:type` (the type of index, supported by some databases)
- * `:where` (partial index, supported by some databases)
-
-
-## Constraints
-
-We can define constraints on columns via `#constraint`. It accepts a **name** and a **block**.
-
-```ruby
-create_table :users do
- # ...
- column :age, Integer
- constraint(:adult_constraint) { age > 18 }
-end
-```
-
-Please note that the block is evaluated in the context of the database engine, **complex Ruby code doesn't work**.
-Database functions are mapped to Ruby functions, but this reduces the portability of the migration.
-
-```ruby
-create_table :users do
- # ...
- column :password, String
- constraint(:password_length_constraint) { char_length(password) >= 8 }
-end
-```
-
-## Checks
-
-Checks are similar to constraints, but they accept an **anonymous block** or a **SQL raw string**.
-
-```ruby
-create_table :users do
- # ...
- column :age, Integer
- column :role, String
-
- check { age > 18 }
- check %(role IN('contributor', 'manager', 'owner'))
-end
-```
diff --git a/source/guides/1.0/migrations/overview.md b/source/guides/1.0/migrations/overview.md
deleted file mode 100644
index ea890d32b..000000000
--- a/source/guides/1.0/migrations/overview.md
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: Guides - Migrations
-version: 1.0
----
-
-# Migrations
-
-Migrations are a feature that allows to manage database schema via Ruby.
-They come with some [command line facilities](/guides/1.0/command-line/database) that allow to perform database operations or to [generate](/guides/1.0/command-line/generators/#migrations) migrations.
-
-Migrations are only available if our application uses the [SQL adapter](/guides/1.0/models/overview).
-
-## Anatomy Of A Migration
-
-Migrations are Ruby files stored by default under `db/migrations`.
-Their name is composed by a UTC timestamp and a snake case name (eg `db/migrations/20150621165604_create_books.rb`).
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-
- column :code, String, null: false, unique: true, size: 128
- column :title, String, null: false
- column :price, Integer, null: false, default: 100 # cents
-
- check { price > 0 }
- end
- end
-end
-```
-
-We use a `create_table` block to define the schema of that table.
-
-The first line is `primary_key :id`, which is a shortcut to create an autoincrement integer column.
-
-There is a `foreign key` definition with cascade deletion.
-The first argument is the name of the local column (`books.author_id`), while the second is the referenced table.
-
-Then we have three lines for columns.
-The first argument that we pass to `column` is the name, then the type.
-The type can be a **Ruby type** such as `String` or `Integer` or a string that represents the **native database type** (eg. `"varchar(32)"` or `"text[]"`).
-
-As a last optional argument there is a Hash that specifies some extra details for the column. For instance NULL or uniqueness constraints, the size (for strings) or the default value.
-
-The final line defines a database **check** to ensure that price will always be greater than zero.
-
-## Up/Down
-
-When we "migrate" a database we are going into an _"up"_ direction because we're adding alterations to it.
-Migrations modifications can be rolled back (_"down"_ direction).
-
-When we use `change` in our migrations, we're implicitly describing _"up"_ modifications.
-Their counterpart can be inferred by `Hanami::Model` when we migrate _"down"_ our database.
-
-Imagine we have the following code:
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :books do
- # ...
- end
- end
-end
-```
-
-When we use `create_table`, Hanami::Model will use `drop_table` in case we want to rollback this migration.
-
-In case we want to have concrete code for our _"down"_ policy, we can use `up` and `down` blocks.
-
-```ruby
-Hanami::Model.migration do
- up do
- create_table :books do
- # ...
- end
- end
-
- down do
- drop_table :books
- end
-end
-```
-
-**To learn how to use migrations in command line, please have a look at [this article](/guides/1.0/command-line/database/#migrate).**
-
-## References
-
-Hanami::Model uses [Sequel](http://sequel.jeremyevans.net/) under the hood as database migration engine. If there is any aspect that isn't covered by our documentation or tests, please refer to [Sequel documentation](http://sequel.jeremyevans.net/rdoc/files/doc/schema_modification_rdoc.html).
diff --git a/source/guides/1.0/models/associations.md b/source/guides/1.0/models/associations.md
deleted file mode 100644
index 4a506a487..000000000
--- a/source/guides/1.0/models/associations.md
+++ /dev/null
@@ -1,198 +0,0 @@
----
-title: Guides - Associations
-version: 1.0
----
-
-# Associations
-
-An association is a logical relationship between two entities.
-
-
- As of the current version, Hanami supports associations as an experimental feature only for the SQL adapter.
-
-
-## Design
-
-Because the association is made of data linked together in a database, we define associations in repositories.
-
-### Explicit Interface
-
-When we declare an association, that repository **does NOT** get any extra method to its public interface.
-This because Hanami wants to prevent to bloat in repositories by adding methods that are often never used.
-
-
- When we define an association, the repository doesn't get any extra public methods.
-
-
-If we need to create an author, contextually with a few books, we need to explicitly define a method to perform that operation.
-
-### Explicit Loading
-
-The same principle applies to read operations: if we want to eager load an author with the associated books, we need an explicit method to do so.
-
-If we don't explicitly load that books, then the resulting data will be `nil`.
-
-### No Proxy Loader
-
-Please remember that operations on associations are made via explicit repository methods.
-Hanami **does NOT** support by design, the following use cases:
-
- * `author.books` (to try to load books from the database)
- * `author.books.where(on_sale: true)` (to try to load _on sale_ books from the database)
- * `author.books << book` (to try to associate a book to the author)
- * `author.books.clear` (to try to unassociate the books from the author)
-
-Please remember that `author.books` is just an array, its mutation **won't be reflected in the database**.
-
-## Types Of Associations
-
-### Has Many
-
-Also known as _one-to-many_, is an association between a single entity (`Author`) and a collection of many other linked entities (`Book`).
-
-```shell
-% bundle exec hanami generate migration create_authors
- create db/migrations/20161115083440_create_authors.rb
-```
-
-```ruby
-# db/migrations/20161115083440_create_authors.rb
-Hanami::Model.migration do
- change do
- create_table :authors do
- primary_key :id
-
- column :name, String, null: false
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```shell
-% bundle exec hanami generate migration create_books
- create db/migrations/20161115083644_create_books.rb
-```
-
-```ruby
-# db/migrations/20161115083644_create_books.rb
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-
- column :title, String, null: false
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```shell
-% bundle exec hanami db prepare
-```
-
-```shell
-% bundle exec hanami generate model author
- create lib/bookshelf/entities/author.rb
- create lib/bookshelf/repositories/author_repository.rb
- create spec/bookshelf/entities/author_spec.rb
- create spec/bookshelf/repositories/author_repository_spec.rb
-
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-Let's edit `AuthorRepository` with the following code:
-
-```ruby
-# lib/bookshelf/repositories/author_repository.rb
-class AuthorRepository < Hanami::Repository
- associations do
- has_many :books
- end
-
- def create_with_books(data)
- assoc(:books).create(data)
- end
-
- def find_with_books(id)
- aggregate(:books).where(id: id).as(Author).one
- end
-end
-```
-
-We have defined [explicit methods](#explicit-interface) only for the operations that we need for our model domain.
-In this way, we avoid to bloat `AuthorRepository` with dozen of unneeded methods.
-
-Let's create an author with a collection of books with a **single database operation**:
-
-```ruby
-repository = AuthorRepository.new
-
-author = repository.create_with_books(name: "Alexandre Dumas", books: [{title: "The Count of Montecristo"}])
- # => #1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC, :books=>[#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]}>
-
-author.id
- # => 1
-author.name
- # => "Alexandre Dumas"
-author.books
- # => [#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]
-```
-
-What happens if we load the author with `AuthorRepository#find`?
-
-```ruby
-author = repository.find(author.id)
- # => #1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>
-author.books
- # => nil
-```
-
-Because we haven't [explicitly loaded](#explicit-loading) the associated records, `author.books` is `nil`.
-We can use the method that we have defined on before (`#find_with_books`):
-
-```ruby
-author = repository.find_with_books(author.id)
- # => #1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC, :books=>[#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]}>
-
-author.books
- # => [#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]
-```
-
-This time `author.books` has the collection of associated books.
-
----
-
-What if we need to add or remove books from an author?
-We need to define new methods to do so.
-
-```ruby
-# lib/bookshelf/repositories/author_repository.rb
-class AuthorRepository < Hanami::Repository
- # ...
-
- def add_book(author, data)
- assoc(:books, author).add(data)
- end
-end
-```
-
-Let's add a book:
-
-```ruby
-book = repository.add_book(author, title: "The Three Musketeers")
-```
-
-And remove it:
-
-```ruby
-BookRepository.new.delete(book.id)
-```
diff --git a/source/guides/1.0/models/data-types.md b/source/guides/1.0/models/data-types.md
deleted file mode 100644
index bd92a7aaf..000000000
--- a/source/guides/1.0/models/data-types.md
+++ /dev/null
@@ -1,90 +0,0 @@
----
-title: Guides - Data Types
-version: 1.0
----
-
-# Data Types
-
-Data types are available for custom [entities schema](/guides/1.0/models/entities#custom-schema), which are *completely optional*.
-
-We have 5 data types:
-
- * **Definition** - base type definition
- * **Strict** - strict type with primitive type check
- * **Coercible** - type with constructor that applies a coercion to given input
- * **Form** - type with constructor that applies a non-strict coercion, specific to HTTP params
- * **JSON** - type with constructor that applies a non-strict coercion, specific to JSON
-
-## Definition
-
- * `Types::Nil`
- * `Types::String`
- * `Types::Symbol`
- * `Types::Int`
- * `Types::Float`
- * `Types::Decimal`
- * `Types::Class`
- * `Types::Bool`
- * `Types::True`
- * `Types::False`
- * `Types::Date`
- * `Types::DateTime`
- * `Types::Time`
- * `Types::Array`
- * `Types::Hash`
-
-## Strict
-
- * `Types::Strict::Nil`
- * `Types::Strict::String`
- * `Types::Strict::Symbol`
- * `Types::Strict::Int`
- * `Types::Strict::Float`
- * `Types::Strict::Decimal`
- * `Types::Strict::Class`
- * `Types::Strict::Bool`
- * `Types::Strict::True`
- * `Types::Strict::False`
- * `Types::Strict::Date`
- * `Types::Strict::DateTime`
- * `Types::Strict::Time`
- * `Types::Strict::Array`
- * `Types::Strict::Hash`
-
-## Coercible
-
- * `Types::Coercible::String`
- * `Types::Coercible::Int`
- * `Types::Coercible::Float`
- * `Types::Coercible::Decimal`
- * `Types::Coercible::Array`
- * `Types::Coercible::Hash`
-
-## Form
-
- * `Types::Form::Nil`
- * `Types::Form::Int`
- * `Types::Form::Float`
- * `Types::Form::Decimal`
- * `Types::Form::Bool`
- * `Types::Form::True`
- * `Types::Form::False`
- * `Types::Form::Date`
- * `Types::Form::DateTime`
- * `Types::Form::Time`
- * `Types::Form::Array`
- * `Types::Form::Hash`
-
-## JSON
-
- * `Types::Json::Nil`
- * `Types::Json::Decimal`
- * `Types::Json::Date`
- * `Types::Json::DateTime`
- * `Types::Json::Time`
- * `Types::Json::Array`
- * `Types::Json::Hash`
-
----
-
-Hanami model data types are based on `dry-types` gem. Learn more at: [http://dry-rb.org/gems/dry-types](http://dry-rb.org/gems/dry-types)
diff --git a/source/guides/1.0/models/database-configuration.md b/source/guides/1.0/models/database-configuration.md
deleted file mode 100644
index ac9394c26..000000000
--- a/source/guides/1.0/models/database-configuration.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Guides - Database Configuration
-version: 1.0
----
-
-# Database Configuration
-
-Before starting your server, you need to configure the database link in .env*
files.
-
-Open this file for each environment and update DATABASE_URL
for your database.
-
-## PostgreSQL
-
-Setup database variable for the development environment:
-
-```
-# .env.development
-DATABASE_URL="postgresql://username:password@localhost/bookshelf_development"
-```
-
-Setup database variable for the test environment:
-
-```
-# .env.test
-DATABASE_URL="postgresql://username:password@localhost/bookshelf_test"
-```
-
-# Setup your database
-
-After your database variables setup is done you need to create the database and run the migrations before being able to launch a development server.
-
-In your terminal, enter:
-
-```
-% bundle exec hanami db prepare
-```
-
-To setup your test environment database, enter:
-
-```
-% HANAMI_ENV=test bundle exec hanami db prepare
-```
diff --git a/source/guides/1.0/models/entities.md b/source/guides/1.0/models/entities.md
deleted file mode 100644
index bcce3b20d..000000000
--- a/source/guides/1.0/models/entities.md
+++ /dev/null
@@ -1,181 +0,0 @@
----
-title: Guides - Entities
-version: 1.0
----
-
-# Entities
-
-An entity is domain object that is defined by its identity.
-
-See ["Domain Driven Design" by Eric Evans](https://en.wikipedia.org/wiki/Domain-driven_design#Building_blocks).
-
-An entity is at the core of an application, where the part of the domain logic is implemented.
-It's a small, cohesive object that expresses coherent and meaningful behaviors.
-
-It deals with one and only one responsibility that is pertinent to the
-domain of the application, without caring about details such as persistence
-or validations.
-
-This simplicity of design allows developers to focus on behaviors, or
-message passing if you will, which is the quintessence of Object Oriented Programming.
-
-## Entity Schema
-
-Internally, an entity holds a schema of the attributes, made of their names and types.
-The role of a schema is to whitelist the data used during the initialization, and to enforce data integrity via coercions or exceptions.
-
-We'll see concrete examples in a second.
-
-### Automatic Schema
-
-When using a SQL database, this is derived automatically from the table definition.
-
-Imagine to have the `books` table defined as:
-
-```sql
-CREATE TABLE books (
- id integer NOT NULL,
- title text,
- created_at timestamp without time zone,
- updated_at timestamp without time zone
-);
-```
-
-This is the corresponding entity `Book`.
-
-```ruby
-# lib/bookshelf/entities/book.rb
-class Book < Hanami::Entity
-end
-```
-
----
-
-Let's instantiate it with proper values:
-
-```ruby
-book = Book.new(title: "Hanami")
-
-book.title # => "Hanami"
-book.created_at # => nil
-```
-
-The `created_at` attribute is `nil` because it wasn't present when we have instantiated `book`.
-
----
-
-It ignores unknown attributes:
-
-```ruby
-book = Book.new(unknown: "value")
-
-book.unknown # => NoMethodError
-book.foo # => NoMethodError
-```
-
-It raises a `NoMethodError` both for `unknown` and `foo`, because they aren't part of the internal schema.
-
----
-
-It can coerce values:
-
-```ruby
-book = Book.new(created_at: "Sun, 13 Nov 2016 09:41:09 GMT")
-
-book.created_at # => 2016-11-13 09:41:09 UTC
-book.created_at.class # => Time
-```
-
-An entity tries as much as it can to coerce values according to the internal schema.
-
----
-
-It enforces **data integrity** via exceptions:
-
-```ruby
-Book.new(created_at: "foo") # => ArgumentError
-```
-
-If we use this feature, in combination with [database constraints](/guides/1.0/migrations/create-table#constraints) and validations, we can guarantee a **strong** level of **data integrity** for our projects.
-
-### Custom Schema
-
-We can take data integrity a step further: we can **optionally** define our own entity internal schema.
-
-
- Custom schema is optional for SQL databases, while it's mandatory for entities without a database table, or while using with a non-SQL database.
-
-
-```ruby
-# lib/bookshelf/entities/user.rb
-class User < Hanami::Entity
- EMAIL_FORMAT = /\@/
-
- attributes do
- attribute :id, Types::Int
- attribute :name, Types::String
- attribute :email, Types::String.constrained(format: EMAIL_FORMAT)
- attribute :age, Types::Int.constrained(gt: 18)
- attribute :codes, Types::Collection(Types::Coercible::Int)
- attribute :comments, Types::Collection(Comment)
- attribute :created_at, Types::Time
- attribute :updated_at, Types::Time
- end
-end
-```
-
-Let's instantiate it with proper values:
-
-```ruby
-user = User.new(name: "Luca", age: 34, email: "luca@hanami.test")
-
-user.name # => "Luca"
-user.age # => 34
-user.email # => "luca@hanami.test"
-user.codes # => nil
-user.comments # => nil
-```
-
----
-
-It can coerce values:
-
-```ruby
-user = User.new(codes: ["123", "456"])
-user.codes # => [123, 456]
-```
-
-Other entities can be passed as concrete instance:
-
-```ruby
-user = User.new(comments: [Comment.new(text: "cool")])
-user.comments
- # => [#"cool"}>]
-```
-
-Or as data:
-
-```ruby
-user = User.new(comments: [{text: "cool"}])
-user.comments
- # => [#"cool"}>]
-```
-
----
-
-It enforces **data integrity** via exceptions:
-
-```ruby
-User.new(email: "foo") # => TypeError: "foo" (String) has invalid type for :email
-User.new(comments: [:foo]) # => TypeError: :foo must be coercible into Comment
-```
-
----
-
-
- Custom schema takes precedence over automatic schema. If we use custom schema, we need to manually add all the new columns from the corresponding SQL database table.
-
-
----
-
-Learn more about data types in the [dedicated article](/guides/1.0/models/data-types).
diff --git a/source/guides/1.0/models/overview.md b/source/guides/1.0/models/overview.md
deleted file mode 100644
index b161cbeff..000000000
--- a/source/guides/1.0/models/overview.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: Guides - Models Overview
-version: 1.0
----
-
-# Models
-
-Hanami's model domain is implemented in a way that separates the behavior that we want to express ([entities](/guides/1.0/models/entities)) from the persistence layer ([repositories](/guides/1.0/models/repositories) and database).
-This design helps keep the interface of our objects small and therefore keeps them fast and reusable.
-
-## Basic Usage
-
-To explain the basic usage, we use a PostgreSQL database.
-
-As first step, we generate the model:
-
-```shell
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create db/migrations/20170406230335_create_books.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-The generator gives us an entity, a repository, a migration, and accompanying test files.
-
-This is the generated entity:
-
-```ruby
-class Book < Hanami::Entity
-end
-```
-
-While this is the generated repository:
-
-```ruby
-class BookRepository < Hanami::Repository
-end
-```
-
-Let's edit the migration with the following code:
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
- column :title, String
- column :created_at, DateTime
- column :updated_at, DateTime
- end
- end
-end
-```
-
-Now we need to prepare the database to use it:
-
-```shell
-% bundle exec hanami db prepare
-```
-
-We're ready to use our repository:
-
-```shell
-% bundle exec hanami console
-irb(main):001:0> book = BookRepository.new.create(title: "Hanami")
-=> #1, :title=>"Hanami", :created_at=>2016-11-13 15:49:14 UTC, :updated_at=>2016-11-13 15:49:14 UTC}>
-```
-
----
-
-Learn more about [repositories](/guides/1.0/models/repositories), [entities](/guides/1.0/models/entities), [migrations](/guides/1.0/migrations/overview), and [database CLI commands](/guides/1.0/command-line/database).
diff --git a/source/guides/1.0/models/postgresql.md b/source/guides/1.0/models/postgresql.md
deleted file mode 100644
index 2645d284e..000000000
--- a/source/guides/1.0/models/postgresql.md
+++ /dev/null
@@ -1,103 +0,0 @@
----
-title: Guides - PostgreSQL
-version: 1.0
----
-
-# PostgreSQL
-
-Hanami natively supports PostgreSQL data types.
-
-Please check your PostgreSQL version for the available features.
-
-## UUID
-
-Here's how to use UUID for a column:
-
-```ruby
-# db/migrations/20161113184557_create_projects.rb
-Hanami::Model.migration do
- up do
- execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
-
- create_table :projects do
- primary_key :id
- column :name, String
- column :token, 'uuid'
- end
- end
-
- down do
- drop_table :projects
- execute 'DROP EXTENSION IF EXISTS "uuid-ossp"'
- end
-end
-```
-
-```ruby
-require "securerandom"
-
-ProjectRepository.new.create(name: "Hanami", token: SecureRandom.uuid)
- # => #1, :name=>"Hanami", :token=>"0aa7ecff-15e4-4aa4-8c00-0e699e2c66f0"}>
-```
-
-### UUID as Primary Key
-
-```ruby
-Hanami::Model.migration do
- up do
- execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
-
- create_table :project_files do
- primary_key :id, 'uuid', null: false, default: Hanami::Model::Sql.function(:uuid_generate_v4)
- column :name, String
- end
- end
-
- down do
- drop_table :project_files
- execute 'DROP EXTENSION IF EXISTS "uuid-ossp"'
- end
-end
-```
-
-```ruby
-ProjectFileRepository.new.create(name: "source.rb")
- # => #"239f8e0f-d764-4a76-aaa7-7b59b5301c72", :name=>"source.rb"}>
-```
-
-## Array
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :articles do
- primary_key :id
- column :title, String
- column :tags, "text[]"
- end
- end
-end
-```
-
-```ruby
-ArticleRepository.new.create(title: "Announcing Hanami 1.0", tags: ["announcements"])
- # => #1, :title=>"Announcing Hanami 1.0", :tags=>["announcements"]}>
-```
-
-## JSON(B)
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :commits do
- primary_key :id
- column :metadata, "jsonb"
- end
- end
-end
-```
-
-```ruby
-CommitRepository.new.create(metadata: { sha: "8775b81" })
- # => #1, :metadata=>{:sha=>"8775b81"}}>
-```
diff --git a/source/guides/1.0/models/repositories.md b/source/guides/1.0/models/repositories.md
deleted file mode 100644
index 971444bab..000000000
--- a/source/guides/1.0/models/repositories.md
+++ /dev/null
@@ -1,303 +0,0 @@
----
-title: Guides - Repositories
-version: 1.0
----
-
-# Repositories
-
-An object that mediates between entities and the persistence layer.
-It offers a standardized API to query and execute commands on a database.
-
-A repository is **storage independent**, all the queries and commands are
-delegated to the current adapter.
-
-This architecture has several advantages:
-
- * Applications depend on a standard API, instead of low level details
- ([Dependency Inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle) principle)
-
- * Applications depend on a stable API, that doesn't change if the
- storage changes
-
- * Developers can postpone storage decisions
-
- * Confines persistence logic to a low level
-
- * Multiple data sources can easily coexist in an application
-
-
- As of the current version, Hanami only supports SQL databases.
-
-
-## Interface
-
-When a class inherits from `Hanami::Repository`, it will receive the following interface:
-
- * `#create(data)` β Create a record for the given data and return an entity
- * `#update(id, data)` β Update the record corresponding to the id and return the updated entity
- * `#delete(id)` β Delete the record corresponding to the given entity
- * `#all` - Fetch all the entities from the collection
- * `#find(id)` - Fetch an entity from the collection by its ID
- * `#first` - Fetch the first entity from the collection
- * `#last` - Fetch the last entity from the collection
- * `#clear` - Delete all the records from the collection
-
-**A collection is a homogenous set of records.**
-It corresponds to a table for a SQL database or to a MongoDB collection.
-
-```ruby
-repository = BookRepository.new
-
-book = repository.create(title: "Hanami")
- # => #1, :title=>"Hanami", :created_at=>2016-11-13 16:02:37 UTC, :updated_at=>2016-11-13 16:02:37 UTC}>
-
-book = repository.find(book.id)
- # => #1, :title=>"Hanami", :created_at=>2016-11-13 16:02:37 UTC, :updated_at=>2016-11-13 16:02:37 UTC}>
-
-book = repository.update(book.id, title: "Hanami Book")
- # => #1, :title=>"Hanami Book", :created_at=>2016-11-13 16:02:37 UTC, :updated_at=>2016-11-13 16:03:34 UTC}>
-
-repository.delete(book.id)
-
-repository.find(book.id)
- # => nil
-```
-
-## Saving more than one record
-
-For saving bunch of records you need to define a `#create_many` command:
-
-```ruby
-class BookRepository
- def create_many(list)
- command(:create, books, result: :many).call(list)
- end
-end
-```
-
-Now you can use `#create_many` as a bulk creation method:
-
-```ruby
-BookRepository.new.create_many([{ title: "Hanami" }, { title: "Ruby"}])
-# => [#, #]
-```
-
-## Private Queries
-
-**All the queries are private**.
-This decision forces developers to define intention revealing API, instead of leaking storage API details outside of a repository.
-
-Look at the following code:
-
-```ruby
-BookRepository.new.where(author_id: 23).order(:published_at).limit(8)
-```
-
-This is **bad** for a variety of reasons:
-
- * The caller has an intimate knowledge of the internal mechanisms of the Repository.
-
- * The caller works on several levels of abstraction.
-
- * It doesn't express a clear intent, it's just a chain of methods.
-
- * The caller can't be easily tested in isolation.
-
- * If we change the storage, we are forced to change the code of the caller(s).
-
-There is a better way:
-
-```ruby
-# lib/bookshelf/repositories/book_repository.rb
-class BookRepository < Hanami::Repository
- def most_recent_by_author(author, limit: 8)
- books
- .where(author_id: author.id)
- .order(:published_at)
- .limit(limit)
- end
-end
-```
-
-This is a **huge improvement**, because:
-
- * The caller doesn't know how the repository fetches the entities.
-
- * The caller works on a single level of abstraction. It doesn't even know about records, only works with entities.
-
- * It expresses a clear intent.
-
- * The caller can be easily tested in isolation. It's just a matter of stubbing this method.
-
- * If we change the storage, the callers aren't affected.
-
-
-
- Hanami queries are based on gems from ROM project, namely
- rom-repository
and rom-sql
.
- The gem rom-sql
is itself based on Sequel project.
-
-
- Learn more on how to craft queries with
- ROM
- and Sequel .
-
-
-
-## Timestamps
-
-To have a track of when a record has been created or updated is important when running a project in production.
-
-When creating a new table, if we add the following columns, a repository will take care of keeping the values updated.
-
-```ruby
-Hanami::Model.migration do
- up do
- create_table :books do
- # ...
- column :created_at, DateTime
- column :updated_at, DateTime
- end
- end
-end
-```
-
-```ruby
-repository = BookRepository.new
-
-book = repository.create(title: "Hanami")
-
-book.created_at # => 2016-11-14 08:20:44 UTC
-book.updated_at # => 2016-11-14 08:20:44 UTC
-
-book = repository.update(book.id, title: "Hanami Book")
-
-book.created_at # => 2016-11-14 08:20:44 UTC
-book.updated_at # => 2016-11-14 08:22:40 UTC
-```
-
-
- When a database table has created_at
and updated_at
timestamps, a repository will automatically update their values.
-
-
-
- Timestamps are on UTC timezone.
-
-
-## Legacy Databases
-
-By default, a repository performs auto-mapping of corresponding database table and creates an [automatic schema](/guides/1.0/models/entities#automatic-schema) for the associated entity.
-
-When working with legacy databases we can resolve the naming mismatch between the table name, the columns, with repositories defaults and entities attributes.
-
-Let's say we have a database table like this:
-
-```sql
-CREATE TABLE t_operator (
- operator_id integer NOT NULL,
- s_name text
-);
-```
-
-We can setup our repository with the following code:
-
-```ruby
-# lib/bookshelf/repositories/operator_repository.rb
-class OperatorRepository < Hanami::Repository
- self.relation = :t_operator
-
- mapping do
- attribute :id, from: :operator_id
- attribute :name, from: :s_name
- end
-end
-```
-
-While the entity can stay with the basic setup:
-
-```ruby
-# lib/bookshelf/entities/operator.rb
-class Operator < Hanami::Entity
-end
-```
-
----
-
-The entity now gets the mapping we defined in the repository:
-
-```ruby
-operator = Operator.new(name: "Jane")
-operator.name # => "Jane"
-```
-
-The repository can use the same mapped attributes:
-
-```ruby
-operator = OperatorRepository.new.create(name: "Jane")
- # => #1, :name=>"Jane"}>
-```
-
-## Count
-
-Count is a concept not generally available to all the databases. SQL databases have it, but others don't.
-
-You can define a method, if you're using a SQL database:
-
-```ruby
-class BookRepository < Hanami::Repository
- def count
- books.count
- end
-end
-```
-
-Or you can expose specific conditions:
-
-```ruby
-class BookRepository < Hanami::Repository
- # ...
-
- def on_sale_count
- books.where(on_sale: true).count
- end
-end
-```
-
-If you want to use raw SQL you can do:
-
-```ruby
-class BookRepository < Hanami::Repository
- # ...
-
- def old_books_count
- books.read("SELECT id FROM books WHERE created_at < (NOW() - 1 * interval '1 year')").count
- end
-end
-```
-
-## Retrieving the first and last records
-
-A repository provides default `#first` and `#last`Β methods, but they don't have any sorting policy.
-
-If you need to specify a custom sorting policy you can use `#order`:
-
-```ruby
-class BookRepository < Hanami::Repository
- # ...
-
- def newest_book
- books.order { created_at }.limit(1).one
- # Passing a symbol instead works too: books.order(:created_at).one
- end
-
- def oldest_book
- books.order { created_at.desc }.limit(1).one
- end
-end
-```
-
-When `#one` is used if no record is find, it returns `nil`.
-
-Please remember to always use `limit(1)`, otherwise `#one` will raise an exception.
-
-You can read more in [this issue](https://github.com/hanami/model/issues/380).
diff --git a/source/guides/1.0/models/sql-queries.md b/source/guides/1.0/models/sql-queries.md
deleted file mode 100644
index 6c7bdf66d..000000000
--- a/source/guides/1.0/models/sql-queries.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-title: Guides - SQL Queries
-version: 1.0
----
-
-## Sort
-
-You can sort records using `#order`:
-
-```ruby
-class UserRepository < Hanami::Repository
- def from_first_to_last
- users.order { created_at.asc }
- end
-
- def from_last_to_first
- users.order { created_at.desc }
- end
-
- def alphabetical
- users.order { name.asc }
- end
-
- def alphabetical_reverse
- users.order { name.asc }
- end
-
- def sort_via_other_relation
- users.order(books[:title].qualified.asc)
- end
-end
-```
-
-## Limit
-
-You can use `#limit` to limit the number of records fetched from the database:
-
-```ruby
-class UserRepository < Hanami::Repository
- def last_created(number)
- users.order { created_at.desc }.limit(number)
- end
-end
-```
-
-## SQL Functions
-
-You can use any SQL functions like `ILIKE`, `IN`, `NOT`, `LENGTH`, etc..
-These functions are available as Ruby methods inside the `#where` block:
-
-```ruby
-class UserRepository < Hanami::Repository
- def by_name(name)
- users.where { name.ilike("%?%", name) }
- end
-
- def by_id_in(input)
- users.where { id.in(input) }
- end
-
- def by_id_in_range(range)
- users.where { id.in(range) }
- end
-
- def by_id_min_max(min, max)
- users.where { id > min || id < max }
- end
-
- def by_not_id(input)
- users.where { id.not(input) }
- end
-
- def by_id_not_in_range(range)
- users.where { id.not(1..100) }
- end
-
- def by_name_length(input)
- users.where { length(:name) > input }
- end
-end
-```
-
-## Joins
-
-You can join several relations:
-
-```ruby
-class BookRepository < Hanami::Repository
- associations do
- has_many :comments
- end
-
- def commented_within(date_range)
- books
- .join(comments)
- .where(comments[:created_at].qualified => date_range)
- .as(Book)
- end
-end
-```
-
-
-For a given relation named :books
, the used foreign key in :comments
is :book_id
. That is the singular name of the relation with \_id
appended to it.
-
-
-In case your database schema doesn't follow this convention above, you can specify an explicit _foreign key_:
-
-```ruby
-class BookRepository < Hanami::Repository
- associations do
- has_many :comments
- end
-
- def commented_within(date_range)
- books
- .join(comments, id: :book_fk_id)
- .where(comments[:created_at].qualified => date_range)
- .as(Book).to_a
- end
-end
-```
-
-You can also use `#inner_join` method.
-
-## Group by
-
-```ruby
-class UserRepository < Hanami::Repository
- associations do
- has_many :books
- end
-
- def users_group_by_id
- users.
- left_join(:books).
- group(:id)
- end
-end
-```
diff --git a/source/guides/1.0/models/use-your-own-orm.md b/source/guides/1.0/models/use-your-own-orm.md
deleted file mode 100644
index c2d9d8734..000000000
--- a/source/guides/1.0/models/use-your-own-orm.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: Guides - Use Your Own ORM
-version: 1.0
----
-
-# Use Your Own ORM
-
-Hanami components are decoupled each other.
-This level of separation allows you to use the ORM (data layer) of your choice.
-
-Here's how to do it:
-
- 1. Edit your `Gemfile`, remove `hanami-model`, add the gem(s) of your ORM and run `bundle install`.
- 2. Remove `lib/` directory (eg. `rm -rf lib`).
- 3. Edit `config/environment.rb`, then remove `require_relative '../lib/bookshelf'` and `model` block in `Hanami.configure`
- 4. Edit `Rakefile` and remove `require 'hanami/rake_tasks'`.
-
-Please notice that if `hanami-model` is removed from the project features like [database commands](/guides/1.0/command-line/database) and [migrations](/guides/1.0/migrations/overview) aren't available.
-
diff --git a/source/guides/1.0/projects/code-reloading.md b/source/guides/1.0/projects/code-reloading.md
deleted file mode 100644
index 976470f55..000000000
--- a/source/guides/1.0/projects/code-reloading.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Guides - Code Reloading
-version: 1.0
----
-
-# Code Reloading
-
-_Code reloading_ allows us to edit code and see the changes with a browser refresh, without needing to stop and restart the [server](/guides/1.0/command-line/applications).
-
-## Development Environment
-
-This is a development-only feature.
-Hanami uses `shotgun` Ruby gem to reload the code as-needed.
-New generated projects have this entry in their `Gemfile`:
-
-```ruby
-group :development do
- # Code reloading
- # See: http://hanamirb.org/guides/1.0/projects/code-reloading
- gem 'shotgun'
-end
-```
-
-Unfortunately, `shotgun` requires that the current environment supports `fork(2)`.
-JRuby and Windows don't support it.
-If this is your case, `shotgun` is not compatible with your development environment, then you can remove that entry from the `Gemfile` or start the server with the `--no-code-reloading` argument.
-
-## Other Environments
-
-Hanami doesn't implement _code reloading_ in its core.
-
-The framework doesn't know about this feature, it just uses Ruby to load the code and execute it. It's `shotgun` that makes _code reloading_ possible, by wrapping Hanami projects' code.
-
-Because `shotgun` is only enabled in development, all the other environments don't have this _code reloading_ feature.
-By excluding this feature from the core of the framework, we make sure that Hanami projects don't mess with Ruby's code loading mechanisms in production.
-
-In other words, once the code is loaded in production, it isn't changed anymore.
diff --git a/source/guides/1.0/projects/initializers.md b/source/guides/1.0/projects/initializers.md
deleted file mode 100644
index 4e16d8db8..000000000
--- a/source/guides/1.0/projects/initializers.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Guides - Project Initializers
-version: 1.0
----
-
-# Initializers
-
-A project can **optionally** have one or more custom initializers.
-
-
- Initializers are optional
-
-
-An initializer is a Ruby file used to setup third-party libraries or some other aspect of the code.
-
-They are run as the **last** thing after the dependencies, the framework and the project code are loaded, but **before** the server or the console is started.
-
-For instance, if we want to setup [Bugsnag](https://bugsnag.com) for our project we can do:
-
-```ruby
-# config/initializers/bugsnag.rb
-require 'bugsnag'
-
-Bugsnag.configure do |config|
- config.api_key = ENV['BUGSNAG_API_KEY']
-end
-```
-
-
- Project initializers must be added under config/initializers
.
-
-
-
- Initializers are executed in alphabetical order.
-
diff --git a/source/guides/1.0/projects/logging.md b/source/guides/1.0/projects/logging.md
deleted file mode 100644
index e9300875a..000000000
--- a/source/guides/1.0/projects/logging.md
+++ /dev/null
@@ -1,89 +0,0 @@
----
-title: Guides - Logging
-version: 1.0
----
-
-# Logging
-
-Each project has a global logger available at `Hanami.logger` that can be used like this: `Hanami.logger.debug "Hello"`
-
-It can be configured in `config/environment.rb`
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :development do
- logger level: :info
- end
-
- environment :production do
- logger level: :info, formatter: :json
-
- # ...
- end
-end
-```
-
-By default it uses standard output because it's a [best practice](http://12factor.net/logs) that most hosting SaaS companies [suggest using](https://devcenter.heroku.com/articles/rails4#logging-and-assets).
-
-If you want to use a file, pass `stream: 'path/to/file.log'` as an option.
-
-## Arbitrary Arguments
-
-You can speficy [arbitrary arguments](https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+create+a+logger), that are compatible with Ruby's `Logger`.
-
-Here's how to setup daily log rotation:
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :production do
- logger 'daily', level: :info, formatter: :json, stream: 'log/production.log'
-
- # ...
- end
-end
-```
-
-Alternatively, you can decide to put a limit to the number of files (let's say `10`) and the size of each file (eg `1,024,000` bytes, aka `1` megabyte):
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :production do
- logger 10, 1_024_000, level: :info, formatter: :json, stream: 'log/production.log'
-
- # ...
- end
-end
-```
-
-## Automatic Logging
-
-All HTTP requests, SQL queries, and database operations are automatically logged.
-
-When a project is used in development mode, the logging format is human readable:
-
-```ruby
-[bookshelf] [INFO] [2017-02-11 15:42:48 +0100] HTTP/1.1 GET 200 127.0.0.1 /books/1 451 0.018576
-[bookshelf] [INFO] [2017-02-11 15:42:48 +0100] (0.000381s) SELECT "id", "title", "created_at", "updated_at" FROM "books" WHERE ("book"."id" = '1') ORDER BY "books"."id"
-```
-
-For production environment, the default format is JSON.
-JSON is parseable and more machine-oriented. It works great with log aggregators or SaaS logging products.
-
-```json
-{"app":"bookshelf","severity":"INFO","time":"2017-02-10T22:31:51Z","http":"HTTP/1.1","verb":"GET","status":"200","ip":"127.0.0.1","path":"/books/1","query":"","length":"451","elapsed":0.000391478}
-```
diff --git a/source/guides/1.0/projects/rake.md b/source/guides/1.0/projects/rake.md
deleted file mode 100644
index 655eba129..000000000
--- a/source/guides/1.0/projects/rake.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-title: Guides - Rake Tasks
-version: 1.0
----
-
-# Rake Tasks
-
-Hanami ships with default Rake tasks that can be used as _prerequisites_ by developers to build their own tasks.
-
-```shell
-% bundle exec rake -T
-rake environment # Load the full project
-rake test # Run tests (for Minitest)
-rake spec # Run tests (for RSpec)
-```
-
-## Environment
-
-Use this as a Rake task prerequisite when we need to access project code (eg. entities, actions, views, etc..)
-
-### Example
-
-Imagine we want to build a Rake task that is able to access project code (eg. a repository)
-
-```ruby
-# Rakefile
-
-task clear_users: :environment do
- UserRepository.new.clear
-end
-```
-
-```shell
-bundle exec rake clear_users
-```
-
-## Test / Spec
-
-This is the default Rake task, which runs the test suite
-
-The following commands are equivalent:
-
-```shell
-% bundle exec rake
-```
-
-```shell
-% bundle exec rake test
-```
-
-
- The :test
(or :spec
) Rake task is the default.
-
-
-## Ruby Server Hosting Ecosystem Compatibility
-
-Many Software as a Service (SaaS) of the Ruby server hosting ecosystem are modeled after Ruby on Rails.
-For instance, Heroku expects to find the following Rake tasks in a Ruby application:
-
- * `db:migrate`
- * `assets:precompile`
-
-For Heroku, there isn't a way to customize the deploy, so we're supporting these "standard" Rake tasks from Ruby on Rails.
-
-**If you are in control of your deployment, don't rely on these Rake tasks, but please use `hanami` [command line](/guides/1.0/command-line/database), instead.**
diff --git a/source/guides/1.0/projects/security.md b/source/guides/1.0/projects/security.md
deleted file mode 100644
index 210a34b94..000000000
--- a/source/guides/1.0/projects/security.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: Guides - Project Security
-version: 1.0
----
-
-# Security
-
-Modern web development has many challenges, and of those security is both very important and often under-emphasized.
-
-Hanami provides ways to secure from most common vulnerabilities. Security options can be configured in application.rb
.
-
-# X-Frame-Options
-
-X-Frame-Options is a HTTP header supported by modern browsers. It determines if a web page can or cannot be included via *<frame>* and *<iframe>* tags by untrusted domains.
-
-Web applications can send this header to prevent Clickjacking attacks:
-
-```ruby
-# Denies all untrusted domains (default)
-security.x_frame_options 'DENY'
-```
-
-```ruby
-# Allows iframes on example.com
-security.x_frame_options 'ALLOW-FROM https://example.com/'
-```
-
-# X-Content-Type-Options
-
-X-Content-Type-Options prevents browsers from interpreting files as something else than declared by the content type in the HTTP headers.
-
-```ruby
-# Will prevent the browser from MIME-sniffing a response away from the declared content-type (default)
-security.x_content_type_options 'nosniff'
-```
-
-# X-XSS-Protection
-
-X-XSS-Protection is a HTTP header to determine the behavior of the browser in case an XSS attack is detected.
-
-
-```ruby
-# Filter enabled. Rather than sanitize the page, when a XSS attack is detected,
-# the browser will prevent rendering of the page (default)
-security.x_xss_protection '1; mode=block'
-```
-
-```ruby
-# Filter disabled
-security.x_xss_protection '0'
-```
-
-```ruby
-# Filter enabled. If a cross-site scripting attack is detected, in order to stop the attack,
-# the browser will sanitize the page
-security.x_xss_protection '1'
-```
-
-```ruby
-# The browser will sanitize the page and report the violation.
-# This is a Chromium function utilizing CSP violation reports to send details to a URI of your choice
-security.x_xss_protection '1; report=http://[YOURDOMAIN]/your_report_URI'
-```
-
-# Content-Security-Policy
-Content-Security-Policy (CSP) is a HTTP header supported by modern browsers. It determines trusted sources of execution for dynamic
-contents (JavaScript) or other web related assets: stylesheets, images, fonts, plugins, etc.
-
-Web applications can send this header to mitigate Cross Site Scripting (XSS) attacks.
-
-The default value allows images, scripts, AJAX, fonts and CSS from the same origin, and does not allow any
-other resources to load (eg object, frame, media, etc).
-
-Inline JavaScript is NOT allowed. To enable it, please use: script-src 'unsafe-inline'
.
-
-Default value is:
-
-```ruby
-security.content_security_policy %{
- form-action 'self';
- frame-ancestors 'self';
- base-uri 'self';
- default-src 'none';
- script-src 'self';
- connect-src 'self';
- img-src 'self' https: data:;
- style-src 'self' 'unsafe-inline' https:;
- font-src 'self';
- object-src 'none';
- plugin-types application/pdf;
- child-src 'self';
- frame-src 'self';
- media-src 'self'
-}
-```
diff --git a/source/guides/1.0/routing/basic-usage.md b/source/guides/1.0/routing/basic-usage.md
deleted file mode 100644
index faab7ca41..000000000
--- a/source/guides/1.0/routing/basic-usage.md
+++ /dev/null
@@ -1,143 +0,0 @@
----
-title: Guides - Basic Usage
-version: 1.0
----
-
-# Basic Usage
-
-## Path matching
-
-In [our initial example](/guides/1.0/routing/overview) we have introduced a really basic relative URI: `/hello`.
-This is what we call _fixed path matching_.
-It is called this because the segment is responsible for responding only to an **exact match**.
-If we visit `/hello`, we get a response.
-If we hit `/foo`, a `404` (Not Found) is returned.
-
-### Fixed Matching
-
-```ruby
-# apps/web/config/routes.rb
-get '/dashboard', to: "dashboard#index"
-```
-
-### Variables
-
-When we have dynamic content to serve, we want our URI to be dynamic as well.
-This can be easily achieved via path variables.
-They are defined with a colon, followed by a name (eg. `:id`).
-
-Once an incoming request is forwarded to our endpoint, we can access the current value in our param's action (`params[:id]`).
-
-```ruby
-get '/books/:id', to: 'books#show'
-```
-
-Multiple variables can be used in a path.
-
-```ruby
-get '/books/:book_id/reviews/:id', to: 'reviews#show'
-```
-
-### Variables Constraints
-
-It's possible to specify constraints for each variable.
-The rule MUST be expressed as a regular expression.
-If a request can satisfy all of them, we're good, otherwise a `404` is returned.
-
-```ruby
-get '/authors/:id', id: /\d+/, to: 'authors#show'
-```
-
-### Optional Tokens
-
-Sometimes we want to specify an optional token as part of our URI.
-It should be expressed between round parentheses.
-If present, it will be available as param in the Rack env, otherwise it will be missing, but the endpoint will be still hit.
-
-```ruby
-get '/books(.:format)', to: 'books#show'
-```
-
-### Wildcard Matching
-
-Imagine we want to serve static files from a user repository.
-It would be impossible to know in advance which files are stored and to prepare routes accordingly.
-
-To solve this problem, Hanami supports _wildcard matching_.
-
-```ruby
-get '/files/*', to: 'files#show'
-```
-
-## Named Routes
-
-We can specify a unique name for each route, in order to generate paths from the router or to test them.
-
-```ruby
-root to: 'home#index'
-get '/hello', to: 'greet#index', as: :greeting
-get '/books/:id', to: 'books#show', as: :book
-```
-
-When a Hanami application starts, it generates a Ruby module at the runtime under our application namespace: eg. `Web.routes`.
-We can use it to generate a relative or absolute URI for our route.
-
-```ruby
-Web.routes.path(:root) # => "/"
-Web.routes.url(:root) # => "http://localhost:2300/"
-
-Web.routes.path(:greeting) # => "/hello"
-Web.routes.url(:greeting) # => "http://localhost:2300/hello"
-```
-
-When we have one or more variables, they can be specified as a Hash.
-
-```ruby
-Web.routes.path(:book, id: 1) # => "/books/1"
-Web.routes.url(:book, id: 1) # => "http://localhost:2300/books/1"
-```
-
-Absolute URL generation is dependent on `scheme`, `host` and `port` settings in `apps/web/application.rb`.
-
-### Routing Helpers
-
-Generating routes from `Web.routes` is helpful, because that module can be accessed from anywhere.
-However, this syntax is noisy.
-
-Hanami has _routing helpers_ available as `routes` in: **actions**, **views** and **templates**.
-
-```ruby
-<%= routes.path(:greeting) %>
-<%= routes.url(:greeting) %>
-```
-
-Or
-
-```ruby
-<%= routes.greeting_path %>
-<%= routes.greeting_url %>
-```
-
-## Namespaces
-
-If we want to group a set of resources under a common prefix we can use `namespace`.
-
-```ruby
-namespace 'docs' do
- get '/installation', to: 'docs#installation'
- get '/usage', to: 'docs#usage'
-end
-
-# This will generate:
-#
-# /docs/installation
-# /docs/usage
-```
-
-## Redirects
-
-In case of legacy routes, we can handle HTTP redirects at the routing level.
-
-```ruby
-redirect '/old', to: '/new'
-```
diff --git a/source/guides/1.0/routing/overview.md b/source/guides/1.0/routing/overview.md
deleted file mode 100644
index 19d53734e..000000000
--- a/source/guides/1.0/routing/overview.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: Guides - Routing Overview
-version: 1.0
----
-
-# Overview
-
-Hanami applications use [Hanami::Router](https://github.com/hanami/router) for routing: a Rack compatible, lightweight and fast HTTP router for Ruby.
-
-## Getting started
-
-With your favorite editor open `apps/web/config/routes.rb` and add the following line.
-
-```ruby
-get '/hello', to: ->(env) { [200, {}, ['Hello from Hanami!']] }
-```
-
-Then start the server with `bundle exec hanami server` and visit [http://localhost:2300/hello](http://localhost:2300/hello).
-You should see `Hello from Hanami!` in your browser.
-
-Let's explain what we just did.
-We created a **route**; an application can have many routes.
-Each route starts with an [HTTP verb](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) declaration, `get` in our case.
-Then we specify a relative URI (`/hello` for us) and the object that is responsible to respond to incoming requests.
-
-We can use most common HTTP verbs: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `TRACE` and `OPTIONS`.
-
-```ruby
-endpoint = ->(env) { [200, {}, ['Hello from Hanami!']] }
-
-get '/hello', to: endpoint
-post '/hello', to: endpoint
-put '/hello', to: endpoint
-patch '/hello', to: endpoint
-delete '/hello', to: endpoint
-trace '/hello', to: endpoint
-options '/hello', to: endpoint
-```
-
-## Rack
-
-Hanami is compatible with [Rack SPEC](http://www.rubydoc.info/github/rack/rack/master/file/SPEC), and so the endpoints that we use MUST be compliant as well.
-In the example above we used a `Proc` that was fitting our requirements.
-
-A valid endpoint can be an object, a class, an action, or an **application** that responds to `#call`.
-
-```ruby
-get '/proc', to: ->(env) { [200, {}, ['Hello from Hanami!']] }
-get '/action', to: "home#index"
-get '/middleware', to: Middleware
-get '/rack-app', to: RackApp.new
-get '/rails', to: ActionControllerSubclass.action(:new)
-```
-
-When we use a string, it tries to instantiate a class from it:
-
-```ruby
-get '/rack-app', to: 'rack_app' # it will map to RackApp.new
-```
-
-## Actions
-
-Full Rack integration is great, but the most common endpoint that we'll use in our web applications is an **action**.
-Actions are objects responsible for responding to incoming HTTP requests.
-They have a nested naming like `Web::Controllers::Home::Index`.
-This is a really long name to write, that's why Hanami has a **naming convention** for it: `"home#index"`.
-
-```ruby
-# apps/web/config/routes.rb
-root to: "home#index" # => will route to Web::Controllers::Home::Index
-```
-
-The first token is the name of the controller `"home"` is translated to `Home`.
-The same transformation will be applied to the name after the `#`: `"index"` to `Index`.
-
-Hanami is able to figure out the namespace (`Web::Controllers`) and compose the full class name.
-
-### Mounting Applications
-
-If we want to mount an application, we should use `mount` within the Hanami environment configuration file. The global configuration file is located at `config/environment.rb`. Place `mount` within the Hanami.configure block.
-
-```ruby
-Hanami.configure do
- mount Web::Application, at: '/'
- mount OtherApplication.new, at: '/other'
-
- ...
-end
-```
-
-#### Mounting To A Path
-
-```ruby
-mount SinatraApp.new, at: '/sinatra'
-```
-
-All the HTTP requests starting with `/sinatra` will be routed to `SinatraApp`.
-
-#### Mounting On A Subdomain
-
-```ruby
-mount Blog.new, host: 'blog'
-```
-
-All the HTTP requests to `http://blog.example.com` will be routed to `Blog`.
-
-
- In development, you will NOT be able to access http://blog.localhost:2300
,
- so you should specify a host when running the server:
- bundle exec hanami server --host=lvh.me
.
- Then your application can be visited at http://blog.lvh.me:2300
-
diff --git a/source/guides/1.0/routing/restful-resources.md b/source/guides/1.0/routing/restful-resources.md
deleted file mode 100644
index 5bbc0330a..000000000
--- a/source/guides/1.0/routing/restful-resources.md
+++ /dev/null
@@ -1,483 +0,0 @@
----
-title: Guides - RESTful Resource(s)
-version: 1.0
----
-
-# REST
-
-Hanami has native [REST](http://en.wikipedia.org/wiki/Representational_state_transfer) support.
-
-At the routing level, there are two methods that can be used to declare them: `resources` and `resource`.
-The former is for plural resources, the latter for singular ones.
-
-Declaring a resource means to generate **several default routes** with just one line of code.
-
-## RESTful Resources
-
-### Default Routes
-
-```ruby
-# apps/web/config/routes.rb
-resources :books
-```
-
-It generates
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /books
- Books::Index
- :index
- :books
-
-
- GET
- /books/:id
- Books::Show
- :show
- :book
-
-
- GET
- /books/new
- Books::New
- :new
- :new_book
-
-
- POST
- /books
- Books::Create
- :create
- :books
-
-
- GET
- /books/:id/edit
- Books::Edit
- :edit
- :edit_book
-
-
- PATCH
- /books/:id
- Books::Update
- :update
- :book
-
-
- DELETE
- /books/:id
- Books::Destroy
- :destroy
- :book
-
-
-
-### Remove Routes
-
-In case we don't need all the default routes we can use `:only` and pass one or more action names.
-We can also black list routes with `:except`.
-
-```ruby
-resources :books, only: [:new, :create, :show]
-
-# equivalent to
-
-resources :books, except: [:index, :edit, :update, :destroy]
-```
-
-### Add Routes
-
-Alongside with default routes we can specify extra routes for single (`member`) or multiple (`collection`) resources.
-
-```ruby
-resources :books do
- member do
- # Generates /books/1/toggle, maps to Books::Toggle, named :toggle_book
- get 'toggle'
- end
-
- collection do
- # Generates /books/search, maps to Books::Search, named :search_books
- get 'search'
- end
-end
-```
-
-### Configure Controller
-
-Imagine we have a controller named `manuscripts`, where we have actions like `Manuscripts::Index`, but we still want to expose those resources as `/books`.
-Using the `:controller` option will save our day.
-
-```ruby
-resources :books, controller: 'manuscripts'
-
-# GET /books/1 will route to Manuscripts::Show, etc.
-```
-
-## RESTful Resource
-
-```ruby
-resource :account
-```
-
-It generates
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /account
- Account::Show
- :show
- :account
-
-
- GET
- /account/new
- Account::New
- :new
- :new_account
-
-
- POST
- /account
- Account::Create
- :create
- :account
-
-
- GET
- /account/edit
- Account::Edit
- :edit
- :edit_account
-
-
- PATCH
- /account
- Account::Update
- :update
- :account
-
-
- DELETE
- /account
- Account::Destroy
- :destroy
- :account
-
-
-
-### Remove Routes
-
-```ruby
-resource :account, only: [:show, :edit, :update, :destroy]
-
-# equivalent to
-
-resource :account, except: [:new, :create]
-```
-
-### Add Routes
-
-```ruby
-resource :account do
- member do
- # Generates /account/avatar, maps to Account::Avatar, named :avatar_account
- get 'avatar'
- end
-
- collection do
- # Generates /account/authorizations, maps to Account::Authorizations, named :authorizations_account
- get 'authorizations'
- end
-end
-```
-
-### Configure Controller
-
-```ruby
-resource :account, controller: 'customer'
-```
-
-## Nested Resource(s)
-
-RESTful resource(s) can be nested in order to make available inner resources inside the scope of their parents.
-
-### Plural to plural
-
-```ruby
-resources :books do
- resources :reviews
-end
-```
-
-**It generates default routes for books and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /books/:book_id/reviews
- Books::Reviews::Index
- :index
- :book_reviews
-
-
- GET
- /books/:book_id/reviews/:id
- Books::Reviews::Show
- :show
- :book_review
-
-
- GET
- /books/:book_id/reviews/new
- Books::Reviews::New
- :new
- :new_book_review
-
-
- POST
- /books/:book_id/reviews
- Books::Reviews::Create
- :create
- :book_reviews
-
-
- GET
- /books/:book_id/reviews/:id/edit
- Books::Reviews::Edit
- :edit
- :edit_book_review
-
-
- PATCH
- /books/:book_id/reviews/:id
- Books::Reviews::Update
- :update
- :book_review
-
-
- DELETE
- /books/:book_id/reviews/:id
- Books::Reviews::Destroy
- :destroy
- :book_review
-
-
-
-### Plural to singular
-
-```ruby
-resources :books do
- resource :cover
-end
-```
-
-**It generates default routes for books and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /books/:book_id/cover
- Books::Cover::Show
- :show
- :book_cover
-
-
- GET
- /books/:book_id/cover/new
- Books::Cover::New
- :new
- :new_book_cover
-
-
- POST
- /books/:book_id/cover
- Books::Cover::Create
- :create
- :book_cover
-
-
- GET
- /books/:book_id/cover/edit
- Books::Cover::Edit
- :edit
- :edit_book_cover
-
-
- PATCH
- /books/:book_id/cover
- Books::Cover::Update
- :update
- :book_cover
-
-
- DELETE
- /books/:book_id/cover
- Books::Cover::Destroy
- :destroy
- :book_cover
-
-
-
-### Singular To Plural
-
-```ruby
-resource :account do
- resources :api_keys
-end
-```
-
-**It generates default routes for account and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /account/api_keys
- Account::ApiKeys::Index
- :index
- :account_api_keys
-
-
- GET
- /account/api_keys/:id
- Account::ApiKeys::Show
- :show
- :account_api_key
-
-
- GET
- /account/api_keys/new
- Account::ApiKeys::New
- :new
- :new_account_api_key
-
-
- POST
- /account/api_keys
- Account::ApiKeys::Create
- :create
- :account_api_keys
-
-
- GET
- /account/api_keys/:id/edit
- Account::ApiKeys::Edit
- :edit
- :edit_account_api_key
-
-
- PATCH
- /account/api_keys/:id
- Account::ApiKeys::Update
- :update
- :account_api_key
-
-
- DELETE
- /account/api_keys/:id
- Account::ApiKeys::Destroy
- :destroy
- :account_api_key
-
-
-
-### Singular To Singular
-
-```ruby
-resource :account do
- resource :avatar
-end
-```
-
-**It generates default routes for account and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /account/avatar
- Account::Avatar::Show
- :show
- :account_avatar
-
-
- GET
- /account/avatar/new
- Account::Avatar::New
- :new
- :new_account_avatar
-
-
- POST
- /account/avatar
- Account::Avatar::Create
- :create
- :account_avatar
-
-
- GET
- /account/avatar/edit
- Account::Avatar::Edit
- :edit
- :edit_account_avatar
-
-
- PATCH
- /account/avatar
- Account::Avatar::Update
- :update
- :account_avatar
-
-
- DELETE
- /account/avatar
- Account::Avatar::Destroy
- :destroy
- :account_avatar
-
-
diff --git a/source/guides/1.0/routing/testing.md b/source/guides/1.0/routing/testing.md
deleted file mode 100644
index 129737e63..000000000
--- a/source/guides/1.0/routing/testing.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Guides - Routing Testing
-version: 1.0
----
-
-# Testing
-
-Hanami has builtin facilities for routing unit tests.
-
-## Path Generation
-
-We can assert the generated routes, to do so, we're gonna create a spec file for the purpose.
-`Web.routes` is the class that holds all the routes for the application named `Web`.
-
-It exposes a method to generate a path, which takes the [name of a route](/guides/1.0/routing/basic-usage#named-routes) as a symbol.
-Here's how to test it.
-
-```ruby
-# spec/web/routes_spec.rb
-RSpec.describe Web.routes do
- it 'generates "/"' do
- actual = described_class.path(:root)
- expect(actual).to eq '/'
- end
-
- it 'generates "/books/23"' do
- actual = described_class.path(:book, id: 23)
- expect(actual).to eq '/books/23'
- end
-end
-```
-
-## Route Recognition
-
-We can also do the opposite: starting from a fake Rack env, we can assert that the recognized route is correct.
-
-```ruby
-# spec/web/routes_spec.rb
-RSpec.describe Web.routes do
-
- # ...
-
- it 'recognizes "GET /"' do
- env = Rack::MockRequest.env_for('/')
- route = described_class.recognize(env)
-
- expect(route).to be_routable
-
- expect(route.path).to eq '/'
- expect(route.verb).to eq 'GET'
- expect(route.params).to eq({})
- end
-
- it 'recognizes "PATCH /books/23"' do
- env = Rack::MockRequest.env_for('/books/23', method: 'PATCH')
- route = described_class.recognize(env)
-
- expect(route).to be_routable
-
- expect(route.path).to eq '/books/23'
- expect(route.verb).to eq 'PATCH'
- expect(route.params).to eq(id: '23')
- end
-
- it 'does not recognize unknown route' do
- env = Rack::MockRequest.env_for('/foo')
- route = subject.recognize(env)
-
- expect(route).to_not be_routable
- end
-end
-```
-
-When we use `.recognize`, the router returns a recognized route, which is an object designed only for testing purposes.
-It carries on all the important information about the route that we have hit.
diff --git a/source/guides/1.0/v060.md b/source/guides/1.0/v060.md
deleted file mode 100644
index e8a4af1b2..000000000
--- a/source/guides/1.0/v060.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.6.0
-version: 1.0
----
-
-## Upgrade Notes for v0.6.0
-
- * Add `SERVE_STATIC_ASSETS="true"` to `.env.development` and `.env.test` in order to serve static assets locally.
-
- * Add `require 'hanami/rake_tasks'` to `Rakefile` in order to enable `:preload` and `:environment` Rake tasks
-
- * Rename `default_format` into `default_request_format` for all the applications (eg. `apps/web/application.rb`)
-
- * Delete all `serve_assets` occurrences from all the applications (eg. `apps/web/application.rb`)
-
- * Create `public/` directory at the root of the project (if not already existing)
-
- * Add `public/assets*` to `.gitignore`
-
- * Rename `apps/web/public` into `apps/web/assets` as assets sources
-
- * Add `require 'hanami/assets'` at the top of `apps/web/application.rb`
-
- * Add `include Web::Assets::Helpers` into `view.prepare` block of `apps/web/application.rb`
-
- * Change assets configuration into `apps/web/application.rb` from:
-
- ```ruby
- assets << [
- # 'vendor/javascripts'
- ]
- ```
-
- to:
-
- ```ruby
- assets do
- javascript_compressor :builtin
- stylesheet_compressor :builtin
-
- sources << [
- 'assets',
- # 'vendor/assets'
- ]
- end
- ```
-
- * Add the following code **inside** the `configure :production` block of `apps/web/application.rb`
-
- ```ruby
- assets do
- compile false
- digest true
-
- # CDN Mode (optional)
- # scheme 'https'
- # host '123.cloudfront.net'
- # port 443
- end
- ```
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.0/v070.md b/source/guides/1.0/v070.md
deleted file mode 100644
index c3685d88a..000000000
--- a/source/guides/1.0/v070.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.7.0
-version: 1.0
----
-
-## Upgrade Notes for v0.7.0
-
- * Rename all the gems in your `Gemfile` from `lotus` to `hanami`
-
- * Rename `.lotusrc` into `.hanamirc`
-
- * Find and replace in project: `lotus` => `hanami`
-
- * Find and replace in project: `Lotus` => `Hanami`
-
- * Find and replace in project: `LOTUS` => `HANAMI`
-
- * Rename the environment variable on your server from `LOTUS_ENV` to `HANAMI_ENV`
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.0/v080.md b/source/guides/1.0/v080.md
deleted file mode 100644
index 3d8e76a49..000000000
--- a/source/guides/1.0/v080.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.8.0
-version: 1.0
----
-
-## Upgrade Notes for v0.8.0
-
- * Use Ruby 2.2+
-
- * Edit your `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 0.8'`.
-
- * Create a group `:development` in `Gemfile` and add `gem 'shotgun'`
-
- * Create a group `:development, :test` in `Gemfile` and add `gem 'dotenv', '~> 2.0'`
-
- * Edit `.hanamirc` by adding a new key `project`. The value must be the snake_case name of the project. Eg. project=active\_citizens
.
-
- * Edit `.env.*` files and change env variables from `_DATABASE_URL` to `DATABASE_URL`.
-
- * Edit `lib/.rb` and change the `adapter -> uri:` variable from `ENV['_DATABASE_URL']` to `ENV['DATABASE_URL']`
-
- * Change params validation syntax. Learn more at [Hanami::Validations README](https://github.com/hanami/validations#usage).
-
- * Change params access syntax to symbols. Eg `params['book']` is no longer supported.
-
- * The returning value of `params.errors` has changed: now it's a Hash with key the attribute name and value an array of strings with error messages.
-
- * In views, layouts and templates use `#local` instead of `#content`, which is now deprecated.
-
- * [Optional] Edit [logging settings](/guides/head/projects/logging) in `apps/web/application.rb`.
-
- * [Optional] Add `security.x_content_type_options 'nosniff'` to `apps/web/application.rb`.
-
- * [Optional] Add `security.x_xss_protection '1; mode=block'` to `apps/web/application.rb`.
-
- * [Optional] Add `subresource_integrity :sha256` to `assets` block in `configure :production` to `apps/web/application.rb`.
-
- * [Optional] Minitest users can disable Rake 11 warnings by adding `t.warning = false` to the `Rake::TestTask.new do |t|` block in `Rakefile`
-
- * [Optional] RSpec users can disable Rake 11 warnings by adding `config.warnings = false ` to the `RSpec.configure |config|` block in spec/spec\_helper.rb
.
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.0/v090.md b/source/guides/1.0/v090.md
deleted file mode 100644
index 6611549f5..000000000
--- a/source/guides/1.0/v090.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.9.0
-version: 1.0
----
-
-## Upgrade Notes for v0.9.0
-
- * Use Ruby 2.3+
-
- * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 0.9'`
-
- * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 0.7'`
-
- * Edit `config/environment.rb` as shown below
-
- * Edit `lib/bookshelf.rb` as shown below
-
- * Edit `spec/spec_helper.rb`, by replacing `Hanami::Application.preload!` with `Hanami.boot`
-
- * Edit `spec/spec_helper.rb`, by adding `Hanami::Utils.require!("spec/support")` (optional)
-
- * Edit `spec/features_helper.rb`, by replacing `Capybara.app = Hanami::Container.new` with `Capybara.app = Hanami.app`
-
- * Edit `config.ru`, by replacing `run Hanami::Container.new` with `run Hanami.app`
-
- * Edit each single application configuration (eg `apps/web/application.rb`) by replacing `digest` with `fingerprint` in `assets` block(s)
-
- * Remove custom subclasses of `Hanami::Model::Coercer` (if any), as PostgreSQL types are now natively supported
-
- * Edit all the repositories (`lib/bookshelf/repositories`) to inherit from `Hanami::Repository` instead of including it
-
- * Edit all the entities (`lib/bookshelf/entities`) to inherit from `Hanami::Entity` instead of including it
-
- * Edit all the repositories by moving the class level methods to instance level
-
- * Update all the repositories with the [new syntax](/guides/head/models/repositories)
-
- * Edit all the entities by removing `.attributes`
-
-### `config/environment.rb`
-
-```ruby
-require 'bundler/setup'
-require 'hanami/setup'
-require 'hanami/model' # Add this line
-require_relative '../lib/bookshelf'
-require_relative '../apps/web/application'
-
-# This used to be `Hanami::Container.configure`, now it must be `Hanami.configure`
-Hanami.configure do
- mount Web::Application, at: '/'
-
- # This is a new block
- #
- # Cut and paste the contents of `Hanami::Model.configure` from lib/bookshelf.rb
- model do
-
- # This used to be:
- #
- # adapter type: :sql, url: ENV['DATABASE_URL']
- adapter :sql, ENV['DATABASE_URL']
-
- migrations 'db/migrations'
- schema 'db/schema.sql'
-
- #
- # Mapping block isn't supported anymore
- #
- end
-
- # This is a new block
- #
- # Cut and paste the contents of `Hanami::Mailer.configure` from lib/bookshelf.rb
- mailer do
-
- # Adjust the new layer `root` location
- root Hanami.root.join("lib", "bookshelf", "mailers")
-
- delivery do
- development :test
- test :test
- # production :smtp, address: ENV['SMTP_PORT'], port: 1025
- end
- end
-end
-```
-
-### `lib/bookshelf.rb`
-
-```ruby
-# This line is enough ;)
-Hanami::Utils.require!("lib/bookshelf")
-```
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.0/v100.md b/source/guides/1.0/v100.md
deleted file mode 100644
index c44701df8..000000000
--- a/source/guides/1.0/v100.md
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: Guides - Upgrade Notes for v1.0.0
-version: 1.0
----
-
-## Upgrade Notes for v1.0.0
-
- * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 1.0'`
-
- * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 1.0'`
-
- * Edit `Gemfile`, by removing Bundler: `gem 'bundler'` can be deleted
-
- * Add `config/boot.rb` as shown below
-
- * Edit `config/environment.rb` as shown below
-
- * Edit `lib/bookshelf.rb` as shown below
-
- * Edit all the applications to remove the `logger` settings. Eg. `apps/web/application.rb`
-
- * Edit the project using `Hanami.logger` instead of application level loggers. Eg. `Web.logger`
-
-
-### `config/boot.rb`
-
-```ruby
-require_relative './environment'
-Hanami.boot
-```
-
-This file can be used to boot your project from external commands. For instance to use it with Sidekiq.
-
-### `config/environment.rb`
-
-```ruby
-require 'bundler/setup'
-require 'hanami/setup'
-require 'hanami/model'
-require_relative '../lib/bookshelf'
-require_relative '../apps/web/application'
-
-Hanami.configure do
- mount Web::Application, at: '/'
-
- model do
- adapter :sql, ENV['DATABASE_URL']
-
- migrations 'db/migrations'
- schema 'db/schema.sql'
- end
-
- mailer do
- # Make sure this folder exists, or delete this row.
- root Hanami.root.join("lib", "bookshelf", "mailers")
-
- # This has changed. It used to be a block, now it's a setting
- delivery :test
- end
-
-Β Β # These two blocks are new.
- # They MUST be after the general settings like `mount`, `model`, `mailer`.
- environment :development do
- # See: http://hanamirb.org/guides/head/projects/logging
- logger level: :info
- end
-
- environment :production do
- logger level: :info, formatter: :json
-
- mailer do
- delivery :smtp, address: ENV['SMTP_HOST'], port: ENV['SMTP_PORT']
- end
- end
-end
-```
-
-### `lib/bookshelf.rb`
-
-```ruby
-module Bookshelf
-end
-```
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.0/validations/advanced-usage.md b/source/guides/1.0/validations/advanced-usage.md
deleted file mode 100644
index 25f6066e6..000000000
--- a/source/guides/1.0/validations/advanced-usage.md
+++ /dev/null
@@ -1,461 +0,0 @@
----
-title: Guides - Advanced Usage
-version: 1.0
----
-
-# Advanced Usage
-
-### Required and Optional keys
-
-HTML forms can have required or optional fields. We can express this concept with two methods in our validations: `required` (which we already met in previous examples), and `optional`.
-
-```ruby
-require 'hanami/validations'
-
-class Signup
- include Hanami::Validations
-
- validations do
- required(:email) { ... }
- optional(:referral) { ... }
- end
-end
-```
-
-### Type Safety
-
-At this point, we need to explicitly tell something really important about built-in predicates. Each of them have expectations about the methods that an input is able to respond to.
-
-Why this is so important? Because if we try to invoke a method on the input weβll get a `NoMethodError` if the input doesnβt respond to it. Which isnβt nice, right?
-
-Before to use a predicate, we want to ensure that the input is an instance of the expected type. Letβs introduce another new predicate for our need: `#type?`.
-
-```ruby
-required(:age) { type?(Integer) & gteq?(18) }
-```
-
-It takes the input and tries to coerce it. If it fails, the execution stops. If it succeed, the subsequent predicates can trust `#type?` and be sure that the input is an integer.
-
-**We suggest to use `#type?` at the beginning of the validations block. This _type safety_ policy is crucial to prevent runtime errors.**
-
-`Hanami::Validations` supports the most common Ruby types:
-
- * `Array` (aliased as `array?`)
- * `BigDecimal` (aliased as `decimal?`)
- * `Boolean` (aliased as `bool?`)
- * `Date` (aliased as `date?`)
- * `DateTime` (aliased as `date_time?`)
- * `Float` (aliased as `float?`)
- * `Hash` (aliased as `hash?`)
- * `Integer` (aliased as `int?`)
- * `String` (aliased as `str?`)
- * `Time` (aliased as `time?`)
-
-For each supported type, there a convenient predicate that acts as an alias. For instance, the two lines of code below are **equivalent**.
-
-```ruby
-required(:age) { type?(Integer) }
-required(:age) { int? }
-```
-
-### Macros
-
-Rule composition with blocks is powerful, but it can become verbose.
-To reduce verbosity, `Hanami::Validations` offers convenient _macros_ that are internally _expanded_ (aka interpreted) to an equivalent _block expression_
-
-#### Filled
-
-To use when we expect a value to be filled:
-
-```ruby
-# expands to
-# required(:age) { filled? }
-
-required(:age).filled
-```
-
-```ruby
-# expands to
-# required(:age) { filled? & type?(Integer) }
-
-required(:age).filled(:int?)
-```
-
-```ruby
-# expands to
-# required(:age) { filled? & type?(Integer) & gt?(18) }
-
-required(:age).filled(:int?, gt?: 18)
-```
-
-In the examples above `age` is **always required** as value.
-
-#### Maybe
-
-To use when a value can be nil:
-
-```ruby
-# expands to
-# required(:age) { none? | int? }
-
-required(:age).maybe(:int?)
-```
-
-In the example above `age` can be `nil`, but if we send the value, it **must** be an integer.
-
-#### Each
-
-To use when we want to apply the same validation rules to all the elements of an array:
-
-```ruby
-# expands to
-# required(:tags) { array? { each { str? } } }
-
-required(:tags).each(:str?)
-```
-
-In the example above `tags` **must** be an array of strings.
-
-
-#### Confirmation
-
-This is designed to check if pairs of web form fields have the same value. One wildly popular example is _password confirmation_.
-
-```ruby
-required(:password).filled.confirmation
-```
-
-It is valid if the input has `password` and `password_confirmation` keys with the same exact value.
-
-β **CONVENTION:** For a given key `password`, the _confirmation_ predicate expects another key `password_confirmation`. Easy to tell, itβs the concatenation of the original key with the `_confirmation` suffix. Their values must be equal. β
-
-### Forms
-
-An important precondition to check before to implement a validator is about the expected input.
-When we use validators for already preprocessed data it's safe to use basic validations from `Hanami::Validations` mixin.
-
-If the data is coming directly from user input via a HTTP form, it's advisable to use `Hanami::Validations::Form` instead.
-**The two mixins have the same API, but the latter is able to do low level input preprocessing specific for forms**. For instance, blank inputs are casted to `nil` in order to avoid blank strings in the database.
-
-### Rules
-
-Predicates and macros are tools to code validations that concern a single key like `first_name` or `email`.
-If the outcome of a validation depends on two or more attributes we can use _rules_.
-
-Here's a practical example: a job board.
-We want to validate the form of the job creation with some mandatory fields: `type` (full time, part-time, contract), `title` (eg. Developer), `description`, `company` (just the name) and a `website` (which is optional).
-An user must specify the location: on-site or remote. If it's on site, they must specify the `location`, otherwise they have to tick the checkbox for `remote`.
-
-Here's the code:
-
-```ruby
-class CreateJob
- include Hanami::Validations::Form
-
- validations do
- required(:type).filled(:int?, included_in?: [1, 2, 3])
-
- optional(:location).maybe(:str?)
- optional(:remote).maybe(:bool?)
-
- required(:title).filled(:str?)
- required(:description).filled(:str?)
- required(:company).filled(:str?)
-
- optional(:website).filled(:str?, format?: URI.regexp(%w(http https)))
-
- rule(location_presence: [:location, :remote]) do |location, remote|
- (remote.none? | remote.false?).then(location.filled?) &
- remote.true?.then(location.none?)
- end
- end
-end
-```
-
-We specify a rule with `rule` method, which takes an arbitrary name and an array of preconditions.
-Only if `:location` and `:remote` are valid according to their validations described above, the `rule` block is evaluated.
-
-The block yields the same exact keys that we put in the precondintions.
-So for `[:location, :remote]` it will yield the corresponding values, bound to the `location` and `remote` variables.
-
-We can use these variables to define the rule. We covered a few cases:
-
- * If `remote` is missing or false, then `location` must be filled
- * If `remote` is true, then `location` must be omitted
-
-### Nested Input Data
-
-While weβre building complex web forms, we may find comfortable to organise data in a hierarchy of cohesive input fields. For instance, all the fields related to a customer, may have the `customer` prefix. To reflect this arrangement on the server side, we can group keys.
-
-```ruby
-validations do
- required(:customer).schema do
- required(:email) { β¦ }
- required(:name) { β¦ }
- # other validations β¦
- end
-end
-```
-
-Groups can be **deeply nested**, without any limitation.
-
-```ruby
-validations do
- required(:customer).schema do
- # other validations β¦
-
- required(:address).schema do
- required(:street) { β¦ }
- # other address validations β¦
- end
- end
-end
-```
-
-### Composition
-
-Until now, we have seen only small snippets to show specific features. That really close view prevents us to see the big picture of complex real world projects.
-
-As the code base grows, itβs a good practice to DRY validation rules.
-
-```ruby
-class AddressValidator
- include Hanami::Validations
-
- validations do
- required(:street) { β¦ }
- end
-end
-```
-
-This validator can be reused by other validators.
-
-```ruby
-class CustomerValidator
- include Hanami::Validations
-
- validations do
- required(:email) { β¦ }
- required(:address).schema(AddressValidator)
- end
-end
-```
-
-Again, there is no limit to the nesting levels.
-
-```ruby
-class OrderValidator
- include Hanami::Validations
-
- validations do
- required(:number) { β¦ }
- required(:customer).schema(CustomerValidator)
- end
-end
-```
-
-In the end, `OrderValidator` is able to validate a complex data structure like this:
-
-```ruby
-{
- number: "123",
- customer: {
- email: "user@example.com",
- address: {
- city: "Rome"
- }
- }
-}
-```
-
-### Whitelisting
-
-Another fundamental role that validators plays in the architecture of our projects is input whitelisting.
-For security reasons, we want to allow known keys to come in and reject everything else.
-
-This process happens when we invoke `#validate`.
-Allowed keys are the ones defined with `.required`.
-
-**Please note that whitelisting is only available for `Hanami::Validations::Form` mixin.**
-
-### Result
-
-When we trigger the validation process with `#validate`, we get a result object in return. Itβs able to tell if itβs successful, which rules the input data has violated and an output data bag.
-
-```ruby
-result = OrderValidator.new({}).validate
-result.success? # => false
-```
-
-#### Messages
-
-`result.messages` returns a nested set of validation error messages.
-
-Each error carries on informations about a single rule violation.
-
-```ruby
-result.messages.fetch(:number) # => ["is missing"]
-result.messages.fetch(:customer) # => ["is missing"]
-```
-
-#### Output
-
-`result.output` is a `Hash` which is the result of whitelisting and coercions. Itβs useful to pass it do other components that may want to persist that data.
-
-```ruby
-{
- "number" => "123",
- "unknown" => "foo"
-}
-```
-
-If we receive the input above, `output` will look like this.
-
-```ruby
-result.output
- # => { :number => 123 }
-```
-
-We can observe that:
-
- * Keys are _symbolized_
- * Only whitelisted keys are included
- * Data is coerced
-
-### Error Messages
-
-To pick the right error message is crucial for user experience.
-As usual `Hanami::Validations` comes to the rescue for most common cases and it leaves space to customization of behaviors.
-
-We have seen that builtin predicates have default messages, while [inline predicates](#inline-custom-predicates) allow to specify a custom message via the `:message` option.
-
-```ruby
-class SignupValidator
- include Hanami::Validations
-
- predicate :email?, message: 'must be an email' do |current|
- # ...
- end
-
- validations do
- required(:email).filled(:str?, :email?)
- required(:age).filled(:int?, gt?: 18)
- end
-end
-
-result = SignupValidator.new(email: 'foo', age: 1).validate
-
-result.success? # => false
-result.messages.fetch(:email) # => ['must be an email']
-result.messages.fetch(:age) # => ['must be greater than 18']
-```
-
-#### Configurable Error Messages
-
-Inline error messages are ideal for quick and dirty development, but we suggest to use an external YAML file to configure these messages:
-
-```yaml
-# config/messages.yml
-en:
- errors:
- email?: "must be an email"
-```
-
-To be used like this:
-
-```ruby
-class SignupValidator
- include Hanami::Validations
- messages_path 'config/messages.yml'
-
- predicate :email? do |current|
- # ...
- end
-
- validations do
- required(:email).filled(:str?, :email?)
- required(:age).filled(:int?, gt?: 18)
- end
-end
-
-```
-
-
-#### Custom Error Messages
-
-In the example above, the failure message for age is fine: `"must be greater than 18"`, but how to tweak it? What if we need to change into something diffent? Again, we can use the YAML configuration file for our purpose.
-
-```yaml
-# config/messages.yml
-en:
- errors:
- email?: "must be an email"
-
- rules:
- signup:
- age:
- gt?: "must be an adult"
-
-```
-
-Now our validator is able to look at the right error message.
-
-```ruby
-result = SignupValidator.new(email: 'foo', age: 1).validate
-
-result.success? # => false
-result.messages.fetch(:age) # => ['must be an adult']
-```
-
-##### Custom namespace
-
-β **CONVENTION:** For a given validator named `SignupValidator`, the framework will look for `signup` translation key. β
-
-If for some reason that doesn't work for us, we can customize the namespace:
-
-```ruby
-class SignupValidator
- include Hanami::Validations
-
- messages_path 'config/messages.yml'
- namespace :my_signup
-
- # ...
-end
-```
-
-The new namespace should be used in the YAML file too.
-
-```yaml
-# config/messages.yml
-en:
- # ...
- rules:
- my_signup:
- age:
- gt?: "must be an adult"
-
-```
-
-#### Internationalization (I18n)
-
-If your project already depends on `i18n` gem, `Hanami::Validations` is able to look at the translations defined for that gem and to use them.
-
-
-```ruby
-class SignupValidator
- include Hanami::Validations
-
- messages :i18n
-
- # ...
-end
-```
-
-```yaml
-# config/locales/en.yml
-en:
- errors:
- signup:
- # ...
-```
diff --git a/source/guides/1.0/validations/boolean-logic.md b/source/guides/1.0/validations/boolean-logic.md
deleted file mode 100644
index 57180eeab..000000000
--- a/source/guides/1.0/validations/boolean-logic.md
+++ /dev/null
@@ -1,192 +0,0 @@
----
-title: Guides - Boolean Logic
-version: 1.0
----
-
-# Boolean Logic
-
-When we check data, we expect only two outcomes: an input can be valid or not. No grey areas, nor fuzzy results. Itβs white or black, 1 or 0, `true` or `false` and _boolean logic_ is the perfect tool to express these two states. Indeed, a Ruby _boolean expression_ can only return `true` or `false`.
-
-To better recognise the pattern, letβs get back to the example above. This time we will map the natural language rules with programming language rules.
-
-```
-required(:name) { filled? & str? & size? (3..64) }
-```
-
-Now, I hope youβll never format code like that, but in this case, that formatting serves well our purpose to show how Rubyβs simplicity helps to define complex rules with no effort.
-
-From a high level perspective, we can tell that input data for `name` is _valid_ only if **all** the requirements are satisfied. Thatβs because we used `&`.
-
-#### Logic Operators
-
-We support four logic operators:
-
- * `&` (aliased as `and`) for _conjunction_
- * `|` (aliased as `or`) for _disjunction_
- * `>` (aliased as `then`) for _implication_
- * `^` (aliased as `xor`) for _exclusive disjunction_
-
-#### Context Of Execution
-
-**Please notice that we used `&` over Ruby's `&&` keyword.**
-That's because the context of execution of these validations isn't a plain lambda, but something richer.
-
-For real world projects, we want to support common scenarios without the need of reinventing the wheel ourselves. Scenarios like _password confirmation_, _size check_ are already prepackaged with `Hanami::Validations`.
-
-
-β **For this reason, we don't allow any arbitrary Ruby code to be executed, but only well defined predicates.** β
-
-### Predicates
-
-To meet our needs, `Hanami::Validations` has an extensive collection of **built-in** predicates. **A predicate is the expression of a business requirement** (e.g. _size greater than_). The chain of several predicates determines if input data is valid or not.
-
-We already met `filled?` and `size?`, now letβs introduce the rest of them. They capture **common use cases with web forms**.
-
-### Array
-
-It checks if the the given value is an array, and iterates through its elements to perform checks on each of them.
-
-```ruby
-required(:codes) { array? { each { int? } } }
-```
-
-This example checks if `codes` is an array and if all the elements are integers, whereas the following example checks there are a minimum of 2 elements and all elements are strings.
-
-```ruby
-required(:codes) { array? { min_size?(2) & each { str? } } }
-```
-
-#### Emptiness
-
-It checks if the given value is empty or not. It is designed to works with strings and collections (array and hash).
-
-```ruby
-required(:tags) { empty? }
-```
-
-#### Equality
-
-This predicate tests if the input is equal to a given value.
-
-```ruby
-required(:magic_number) { eql?(23) }
-```
-
-Ruby types are respected: `23` (an integer) is only equal to `23`, and not to `"23"` (a string). See _Type Safety_ section.
-
-#### Exclusion
-
-It checks if the input is **not** included by a given collection. This collection can be an array, a set, a range or any object that responds to `#include?`.
-
-```ruby
-required(:genre) { excluded_from?(%w(pop dance)) }
-```
-
-#### Format
-
-This is a predicate that works with a regular expression to match it against data input.
-
-```ruby
-require 'uri'
-HTTP_FORMAT = URI.regexp(%w(http https))
-
-required(:url) { format?(HTTP_FORMAT) }
-```
-
-#### Greater Than
-
-This predicate works with numbers to check if input is **greater than** a given threshold.
-
-```ruby
-required(:age) { gt?(18) }
-```
-
-#### Greater Than Equal
-
-This is an _open boundary_ variation of `gt?`. It checks if an input is **greater than or equal** of a given number.
-
-```ruby
-required(:age) { gteq?(19) }
-```
-
-#### Inclusion
-
-This predicate is the opposite of `#exclude?`: it verifies if the input is **included** in the given collection.
-
-```ruby
-required(:genre) { included_in?(%w(rock folk)) }
-```
-
-#### Less Than
-
-This is the complement of `#gt?`: it checks for **less than** numbers.
-
-```ruby
-required(:age) { lt?(7) }
-```
-
-#### Less Than Equal
-
-Similarly to `#gteq?`, this is the _open bounded_ version of `#lt?`: an input is valid if itβs **less than or equal** to a number.
-
-```ruby
-required(:age) { lteq?(6) }
-```
-
-#### Filled
-
-Itβs a predicate that ensures data input is filled, that means **not** `nil` or blank (`""`) or empty (in case we expect a collection).
-
-```ruby
-required(:name) { filled? } # string
-required(:languages) { filled? } # collection
-```
-
-#### Minimum Size
-
-This verifies that the size of the given input is at least of the specified value.
-
-```ruby
-required(:password) { min_size?(12) }
-```
-
-#### Maximum Size
-
-This verifies that the size of the given input is at max of the specified value.
-
-```ruby
-required(:name) { max_size?(128) }
-```
-
-#### None
-
-This verifies if the given input is `nil`. Blank strings (`""`) wonβt pass this test and return `false`.
-
-```ruby
-required(:location) { none? }
-```
-
-#### Size
-
-It checks if the size of input data is: a) exactly the same of a given quantity or b) it falls into a range.
-
-```ruby
-required(:two_factor_auth_code) { size?(6) } # exact
-required(:password) { size?(8..32) } # range
-```
-
-The check works with strings and collections.
-
-```ruby
-required(:answers) { size?(2) } # only 2 answers are allowed
-```
-
-This predicate works with objects that respond to `#size`. Until now we have seen strings and arrays being analysed by this validation, but there is another interesting usage: files.
-
-When a user uploads a file, the web server sets an instance of `Tempfile`, which responds to `#size`. That means we can validate the weight in bytes of file uploads.
-
-```ruby
-MEGABYTE = 1024 ** 2
-
-required(:avatar) { size?(1..(5 * MEGABYTE)) }
-```
diff --git a/source/guides/1.0/validations/custom-predicates.md b/source/guides/1.0/validations/custom-predicates.md
deleted file mode 100644
index cd96d931f..000000000
--- a/source/guides/1.0/validations/custom-predicates.md
+++ /dev/null
@@ -1,64 +0,0 @@
----
-title: Guides - Custom Predicates
-version: 1.0
----
-
-# Custom Predicates
-
-We have seen that built-in predicates as an expressive tool to get our job done with common use cases.
-
-But what if our case is not common? We can define our own custom predicates.
-
-#### Inline Custom Predicates
-
-If we are facing a really unique validation that don't need to be reused across our code, we can opt for an inline custom predicate:
-
-```ruby
-require 'hanami/validations'
-
-class Signup
- include Hanami::Validations
-
- predicate :url?, message: 'must be an URL' do |current|
- # ...
- end
-
- validations do
- required(:website) { url? }
- end
-end
-```
-
-#### Global Custom Predicates
-
-If our goal is to share common used custom predicates, we can include them in a module to use in all our validators:
-
-```ruby
-require 'hanami/validations'
-
-module MyPredicates
- include Hanami::Validations::Predicates
-
- self.messages_path = 'config/errors.yml'
-
- predicate(:email?) do |current|
- current.match(/.../)
- end
-end
-```
-
-We have defined a module `MyPredicates` with the purpose to share its custom predicates with all the validators that need them.
-
-```ruby
-require 'hanami/validations'
-require_relative 'my_predicates'
-
-class Signup
- include Hanami::Validations
- predicates MyPredicates
-
- validations do
- required(:email) { email? }
- end
-end
-```
diff --git a/source/guides/1.0/validations/overview.md b/source/guides/1.0/validations/overview.md
deleted file mode 100644
index 21bf398f9..000000000
--- a/source/guides/1.0/validations/overview.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Guides - Validations Overview
-version: 1.0
----
-
-# Overview
-
-`Hanami::Validations` is a mixin that, once included by an object, adds lightweight set of validations to it.
-
-It works with input hashes and lets us to define a set of validation rules **for each** key/value pair. These rules are wrapped by lambdas (or special DSL) that check the input for a specific key to determine if it's valid or not. To do that, we translate business requirements into predicates that are chained together with Ruby _faux boolean logic_ operators (eg. `&` or `|`).
-
-Think of a signup form. We need to ensure data integrity for the `name` field with the following rules. It is required, it has to be: filled **and** a string **and** its size must be greater than 3 chars, but lesser than 64. Hereβs the code, **read it aloud** and notice how it perfectly expresses our needs for `name`.
-
-```ruby
-class Signup
- include Hanami::Validations
-
- validations do
- required(:name) { filled? & str? & size?(3..64) }
- end
-end
-
-result = Signup.new(name: "Luca").validate
-result.success? # => true
-```
-
-There is more that `Hanami::Validations` can do: **type safety**, **composition**, **complex data structures**, **built-in and custom predicates**.
diff --git a/source/guides/1.0/views/basic-usage.md b/source/guides/1.0/views/basic-usage.md
deleted file mode 100644
index f4f376497..000000000
--- a/source/guides/1.0/views/basic-usage.md
+++ /dev/null
@@ -1,118 +0,0 @@
----
-title: Guides - Views Basic Usage
-version: 1.0
----
-
-# Basic Usage
-
-In the [previous section](/guides/1.0/views/overview) we generated a view. Let's use it.
-
-## Default Rendering
-
-First, we edit the corresponding template:
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-Dashboard
-```
-
-By visiting `/dashboard`, we should see `Dashboard ` in our browser.
-
-Again we should look at the naming convention.
-Our view is `Web::Views::Dashboard::Index`, while the file name of the template is `web/templates/dashboard/index`.
-
-
- For a given view Web::Views::Dashboard::Index
, the corresponding template MUST be available at apps/web/templates/dashboard/index.html.erb
.
-
-
-### Context
-
-While rendering a template, variable lookups requested by the template go to a view _context_.
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-<%= title %>
-```
-
-If we amend our template by adding an interpolated variable, the view is responsible for providing it.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
-
- def title
- 'Dashboard'
- end
- end
-end
-```
-
-The view now responds to `#title` by implementing it as a concrete method.
-We still see `Dashboard ` when we visit `/dashboard`.
-
-### Exposures
-
-There is another source for our context: [_exposures_](/guides/1.0/actions/exposures).
-They are a payload that comes from the action.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- expose :title
-
- def call(params)
- @title = 'Dashboard'
- end
- end
-end
-```
-
-We can remove `#title` from our view, to get the same output when accessing `/dashboard`.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- end
-end
-```
-
-
-Rendering context for a template is made of view methods and exposures.
-
-
-## Custom Rendering
-
-Hanami performs rendering by calling `#render` on a view and it expects a string in return.
-The benefit of an object-oriented approach is the ability to easily diverge from default behavior.
-
-We can override that method to define a custom rendering policy.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
-
- def render
- raw %(Dashboard )
- end
- end
-end
-```
-
-Once again our output is still the same, but the template isn't used at all.
-
-
-If a view overrides #render
the output MUST be a string that will be the body of the response.
-The template isn't used and it can be deleted.
-
-
-## Bypass Rendering
-
-If an action assigns the body of the response with `#body=`, the rendering of the view is [bypassed](/guides/1.0/actions/basic-usage).
diff --git a/source/guides/1.0/views/custom-error-pages.md b/source/guides/1.0/views/custom-error-pages.md
deleted file mode 100644
index 594b89951..000000000
--- a/source/guides/1.0/views/custom-error-pages.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Guides - Custom Error Pages
-version: 1.0
----
-
-# Custom Error Pages
-
-When an unsuccessful request is returned, there are some special pages that a Hanami application presents to users.
-These pages have a generic graphic and some basic information like the [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) and the message.
-
-Hanami allows us to customize them on a per-application basis.
-We just need to create a template with the corresponding HTTP code as the filename (e.g. `apps/web/templates/500.html.erb`).
-From then on, all 500 errors (Internal Server Error) will be presented using that template (like for an exception that is not rescued).
-
-
- A template for a custom error page MUST be named after the HTTP code that it targets.
- Example: 500.html.erb
for Internal Server Error (500).
-
-
-
- A template for a custom error page MUST be placed under the templates
directory of the application.
-
diff --git a/source/guides/1.0/views/layouts.md b/source/guides/1.0/views/layouts.md
deleted file mode 100644
index ea2ad70d5..000000000
--- a/source/guides/1.0/views/layouts.md
+++ /dev/null
@@ -1,146 +0,0 @@
----
-title: Guides - View Layouts
-version: 1.0
----
-
-# Layouts
-
-Layouts are special views, that render the _"fixed"_ part of the HTML markup.
-This is the part that doesn't change from page to page (perhaps navigation, sidebar, header, footer, etc.)
-
-When we generate a new application, there is a default layout called `Web::Views::ApplicationLayout` with a `apps/web/templates/application.html.erb` template.
-It comes with a very basic HTML5 wireframe.
-
-```erb
-
-
-
- Web
-
-
- <%= yield %>
-
-
-```
-
-The most interesting part is `<%= yield %>`.
-It's replaced at the runtime with the output of a view.
-**The order for rendering is first the view, and then the layout.**
-
-The context for a layout template is made of the layout and the current view.
-The latter has higher priority.
-
-Imagine having the following line `<%= page_title %> `.
-If both the layout and the view implement `page_title`, Hanami will use the one from the view.
-
-## Configure Layout
-
-The default layout is defined in an application's configuration.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- layout :application
- end
- end
-end
-```
-
-
-Hanami transforms the layout name in the application's configuration, by appending the Layout
suffix. For example, layout :application
corresponds to Web::Views::ApplicationLayout
.
-
-
-If we want to disable a layout for a view, we can use a DSL for that:
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- layout false
- end
-end
-```
-
-If we want to turn off this feature entirely, we can set `layout nil` into the application's configuration.
-
-## Using Multiple Template Layouts
-
-Sometimes it's useful to have more than one layout.
-For example, if the `application.html.erb` template contains navigation elements, and we want an entirely different layout, without navigation elements, for a login page, we can create a `login.html.erb` layout template.
-
-Assuming we have a `Web::Actions::UserSessions::New` action to log a user in, we can create a `login.html.erb` template right next to the default `application.html.erb` in `apps/web/templates/`.
-
-Then we need to create a new `Web::Views::LoginLayout` class, which will use the new layout template. This file can be named `app/web/views/login_layout.rb`(right next to the default `application_layout.rb`):
-
-```ruby
-module Web
- module Views
- class LoginLayout
- include Web::Layout
- end
- end
-end
-```
-
-Now, in our `app/web/views/user_sessions/new.rb` we can specify you'd like to use the login layout for this View:
-
-```ruby
-module Web::Views::UserSessions
- class New
- include Web::View
- layout :login
- end
-end
-```
-
-And we can add `layout :login` to any other View in this app that should use this same layout.
-
-## Optional Content
-
-Sometimes it's useful to render content only on certain pages.
-For example, this could be used to have page-specific javascript.
-
-Given the following template for a layout:
-
-```erb
-
-
-
-
-
-
- <%= local :javascript %>
-
-
-
-```
-
-With following views:
-
-```ruby
-module Web::Views::Books
- class Index
- include Web::View
- end
-end
-```
-
-and
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def javascript
- raw %()
- end
- end
-end
-```
-
-The first view doesn't respond to `#javascript`, so it safely ignores it.
-Our second object (`Web::Views::Books::Show`) responds to that method, so the result will be included in the final markup.
diff --git a/source/guides/1.0/views/mime-types.md b/source/guides/1.0/views/mime-types.md
deleted file mode 100644
index 5c6c4cb64..000000000
--- a/source/guides/1.0/views/mime-types.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: Guides - MIME Types
-version: 1.0
----
-
-# MIME Types
-
-A view can handle several MIME Types. Before diving into this subject, please consider to read how actions handle [MIME Types](/guides/1.0/actions/mime-types).
-
-It's important to highlight the correlation between the _format_ and template name.
-For a given MIME Type, Rack (and then Hanami) associate a _format_ for it.
-XML is mapped from `application/xml` to `:xml`, HTML is `text/html` and becomes `:html` for us.
-
-
-Format MUST be the first extension of the template file name. Eg dashboard/index.html.*
.
-
-
-## Default Rendering
-
-If our action (`Web::Controllers::Dashboard::Index`) is handling a JSON request, and we have defined a template for it (`apps/web/templates/dashboard/index.json.erb`), our view will use it for rendering.
-
-```erb
-# apps/web/templates/dashboard/index.json.erb
-{"foo":"bar"}
-```
-
-```shell
-% curl -H "Accept: application/json" http://localhost:2300/dashboard
-{"foo":"bar"}
-```
-
-We're still able to request HTML format.
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-Dashboard
-```
-
-```shell
-% curl -H "Accept: text/html" http://localhost:2300/dashboard
-Dashboard
-```
-
-In case we request an unsupported MIME Type, our application will raise an error.
-
-```shell
-% curl -H "Accept: application/xml" http://localhost:2300/dashboard
-Hanami::View::MissingTemplateError: Can't find template "dashboard/index" for "xml" format.
-```
-
-## View For Specific Format
-
-This scenario works well if the presentational logic of a view can be applied for all the format templates that it handles.
-What if we want to have a [custom rendering](/guides/1.0/views/basic-usage) or different presentational logic?
-
-We can inherit from our view and declare that our subclass only handles a specific format.
-
-```ruby
-# apps/web/views/dashboard/json_index.rb
-require_relative './index'
-
-module Web::Views::Dashboard
- class JsonIndex < Index
- format :json
-
- def render
- raw JSON.generate({foo: 'bar'})
- end
- end
-end
-```
-
-JSON requests for `/dashboard`, will be handled by our `JsonIndex`.
-
-
-There is NO convention between the handled format and the class name. The important part is format :json
.
-
-
-With the example above we took advantage of custom rendering to not use the template and let our serializer to return JSON for us.
diff --git a/source/guides/1.0/views/overview.md b/source/guides/1.0/views/overview.md
deleted file mode 100644
index 260409223..000000000
--- a/source/guides/1.0/views/overview.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Guides - Views Overview
-version: 1.0
----
-
-# Overview
-
-A view is an object that's responsible for rendering a template.
-
-In a full stack Hanami application, an incoming HTTP request goes through the [router](/guides/1.0/routing/overview), it instantiates and calls an [action](/guides/1.0/actions/overview), which sets the status code and the headers for the response.
-The last bit is the body, which is set by the corresponding view's output.
-
-## A Simple View
-
-Hanami ships a generator for actions that creates a view and a template.
-
-```shell
-% hanami generate action web dashboard#index
- insert apps/web/config/routes.rb
- create spec/web/controllers/dashboard/index_spec.rb
- create apps/web/controllers/dashboard/index.rb
- create apps/web/views/dashboard/index.rb
- create apps/web/templates/dashboard/index.html.erb
- create spec/web/views/dashboard/index_spec.rb
-```
-
-Looking at those file names, we have an action called `Web::Controllers::Dashboard::Index` (read about [actions naming](/guides/1.0/actions/overview)).
-Our view has a similar name: `Web::Views::Dashboard::Index`.
-
-Let's examine the view:
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- end
-end
-```
-
-### Naming
-
-That file begins with a module declaration which is similar to the [action naming structure](/guides/1.0/actions/overview).
-The only difference is that we use `Views` module instead of `Controllers`.
-**All the views are nested under it.**
-This module is generated at the runtime for us, when the application starts.
-
-
- For a given application named Web
, views are available under Web::Views
.
-
-
-**This symmetry is really important at run time.**
-After the action has finished its job, control passes to the framework which looks for the matching view.
-
-
- For a given action named Web::Controllers::Home::Index
which is handling a request, Hanami will look for a corresponding Web::Views::Home::Index
view.
-
-
-### View Module
-
-All the main Hanami components are mixins meant to be included.
-Because a Hanami Container can run multiple applications within the same Ruby process, the configurations of these different components should be kept separated.
-
-In our example, we have a directive `include Web::View`.
-That means our view will behave according to the configuration of the `Web` application.
-
-
- For a given application named Web
, the view mixin to include is Web::View
.
-
diff --git a/source/guides/1.0/views/share-code.md b/source/guides/1.0/views/share-code.md
deleted file mode 100644
index 7953c4b89..000000000
--- a/source/guides/1.0/views/share-code.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Guides - View Share Code
-version: 1.0
----
-
-# Share Code
-
-## Prepare
-
-In our settings (`apps/web/application.rb`), there is a code block that allows to share the code for **all the views** of our application.
-When a view includes the `Web::View` module, that block code is yielded within the context of that class.
-This is heavily inspired by Ruby Module and its `included` hook.
-
-Imagine we have an application that only renders JSON.
-For each view we should specify the handled format. This can be tedious to do by hand, but we can easily DRY our code.
-
-We craft a module in `apps/web/views/accept_json.rb`.
-
-```ruby
-# apps/web/views/accept_json.rb
-module Web::Views
- module AcceptJson
- def self.included(view)
- view.class_eval do
- format :json
- end
- end
- end
-end
-```
-
-Then we can load the file and include the module in **all** the views of our application, using view.prepare.
-
-```ruby
-# apps/web/application.rb
-require_relative './views/accept_json'
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- view.prepare do
- include Web::Views::AcceptJson
- end
- end
- end
-end
-```
-
-
-Code included via prepare
is available for ALL the views of an application.
-
diff --git a/source/guides/1.0/views/templates.md b/source/guides/1.0/views/templates.md
deleted file mode 100644
index 445ae05f0..000000000
--- a/source/guides/1.0/views/templates.md
+++ /dev/null
@@ -1,216 +0,0 @@
----
-title: Guides - View Templates
-version: 1.0
----
-
-# Templates
-
-A template is a file that describes the body of a response.
-It is rendered by bounding the context of a view and using a _template engine_.
-
-## Naming
-
-For simplicity sake, there is a correlation between the view class name and the template file name.
-It's the translation of the name into a path: from `Dashboard::Index` to `dashboard/index`.
-
-The remaining part is made of multiple file extensions.
-The first is relative to the **_format_** and the latter is for the **_template engine_**.
-
-
-For a given view named Web::Views::Dashboard::Index
, there must be at least one template dashboard/index.[format].[engine]
under the templates directory.
-
-
-## Nested Templates
-To render a partial in other template call `render` method with `partial` option:
-
-```
-# Given a partial under:
-# templates/shared/_sidebar.html.erb
-#
-# In the layout template:
-# templates/application.html.erb
-#
-<%= render partial: 'shared/sidebar' %>
-```
-
-To render a template in other template call `render` method with `template` option:
-
-```
-# Given a template under:
-# templates/articles/index.html.erb
-#
-# In the layout template:
-# templates/application.html.erb
-#
-<%= render template: 'articles/index' %>
-```
-
-### Custom Template
-
-If we want to associate a different template to a view, we can use `template`.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- template 'home/index'
- end
-end
-```
-
-Our view will look for `apps/web/templates/home/index.*` template.
-
-## Engines
-
-Hanami looks at the last extension of a template file name to decide which engine to use (eg `index.html.erb` will use ERb).
-The builtin rendering engine is [ERb](http://en.wikipedia.org/wiki/ERuby), but Hanami supports countless rendering engines out of the box.
-
-This is a list of the supported engines.
-They are listed in order of **higher precedence**, for a given extension.
-For instance, if [ERubis](http://www.kuwata-lab.com/erubis/) is loaded, it will be preferred over ERb to render `.erb` templates.
-
-
-
- Engine
- Extensions
-
-
- Erubis
- erb, rhtml, erubis
-
-
- ERb
- erb, rhtml
-
-
- Redcarpet
- markdown, mkd, md
-
-
- RDiscount
- markdown, mkd, md
-
-
- Kramdown
- markdown, mkd, md
-
-
- Maruku
- markdown, mkd, md
-
-
- BlueCloth
- markdown, mkd, md
-
-
- Asciidoctor
- ad, adoc, asciidoc
-
-
- Builder
- builder
-
-
- CSV
- rcsv
-
-
- CoffeeScript
- coffee
-
-
- WikiCloth
- wiki, mediawiki, mw
-
-
- Creole
- wiki, creole
-
-
- Etanni
- etn, etanni
-
-
- Haml
- haml
-
-
- Less
- less
-
-
- Liquid
- liquid
-
-
- Markaby
- mab
-
-
- Nokogiri
- nokogiri
-
-
- Plain
- html
-
-
- RDoc
- rdoc
-
-
- Radius
- radius
-
-
- RedCloth
- textile
-
-
- Sass
- sass
-
-
- Scss
- scss
-
-
- Slim
- slim
-
-
- String
- str
-
-
- Yajl
- yajl
-
-
-
-In order to use a different template engine we need to bundle the gem and to use the right file extension.
-
-```haml
-# app/web/templates/dashboard/index.html.haml
-%h1 Dashboard
-```
-
-## Directory
-
-Templates are located in the default directory `templates`, located under an application's directory `apps/web`.
-If we want to customize this location, we can amend our application's configuration.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- templates 'path/to/templates'
- end
- end
-end
-```
-
-The application will now look for templates under `apps/web/path/to/templates`.
diff --git a/source/guides/1.0/views/testing.md b/source/guides/1.0/views/testing.md
deleted file mode 100644
index cf25c4a33..000000000
--- a/source/guides/1.0/views/testing.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-title: Guides - View Testing
-version: 1.0
----
-
-# View Testing
-
-One of the advantages of views as objects is that we can unit test them.
-We can both understand if a specific presentational logic behaves correctly and/or assert the contents of the rendered markup.
-
-For the following example we're gonna use RSpec for the concise syntax for test doubles.
-
-```ruby
-# spec/web/views/books/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/views/books/show'
-
-RSpec.describe Web::Views::Books::Show do
- let(:exposures) { Hash[book: double('book', price: 1.00), current_user: user, params: {}] }
- let(:template) { Hanami::View::Template.new('apps/web/templates/books/show.html.erb') }
- let(:view) { Web::Views::Home::Another.new(template, exposures) }
- let(:rendered) { view.render }
- let(:user) { double('user', admin?: false) }
-
- describe "price" do
- it "returns formatted price" do
- expect(view.formatted_price).to eq "$1.00"
- end
- end
-
- describe "edit link" do
- it "doesn't show it by default" do
- expect(rendered).to_not match %(edit )
- end
-
- context "when admin" do
- let(:user) { double('user', admin?: true) }
-
- it "shows it" do
- expect(rendered).to match %(edit )
- end
- end
- end
-end
-```
-
-The first part of the test code above is about book's formatting price.
-This presentational logic is verified by asserting the returning value of `view.formatted_price`.
-
-The remaining code is about permissions related logic: the edit link must be rendered only if the current user is an admin.
-This is tested by looking at the output of the template.
-
-
- Asserting presentational logic directly via view's methods, or indirectly via rendered markup are two EQUIVALENT ways.
-
-
-Notice that `exposures` includes an unused `params` key.
-While this is not strictly required,
-we recommend providing it since it's expected by some standard view helpers (e.g. form helpers).
-
-Let's have a look at the corresponding production code.
-
-```ruby
-# apps/web/views/books/show.rb
-module Web::Views::Books
- class Show
- include Web::View
-
- def formatted_price
- "$#{ format_number book.price }"
- end
-
- def edit_link
- if can_edit_book?
- link_to "Edit", routes.edit_book_path(id: book.id)
- end
- end
-
- private
-
- def can_edit_book?
- current_user.admin?
- end
- end
-end
-```
diff --git a/source/guides/1.1/actions/basic-usage.md b/source/guides/1.1/actions/basic-usage.md
deleted file mode 100644
index 395f5709b..000000000
--- a/source/guides/1.1/actions/basic-usage.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-title: Guides - Actions Basic Usage
-version: 1.1
----
-
-# Basic Usage
-
-## Requests Handling
-
-In the [previous section](/guides/1.1/actions/overview), we generated an action. Now let's use it.
-
-First, we check our routes:
-
-```ruby
-# apps/web/config/routes.rb
-get '/dashboard', to: 'dashboard#index'
-```
-
-### View Rendering
-
-Then we edit the corresponding template:
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-Dashboard
-```
-
-Here is how Hanami handles an incoming request:
-
- 1. The router creates a new instance of `Web::Controllers::Dashboard::Index` and invokes `#call`.
- 2. The application creates a new instance of `Web::Views::Dashboard::Index` and invokes `#render`.
- 3. The application returns the response to the browser.
-
-
- For a given action named Web::Controllers::Dashboard::Index
, a corresponding view MUST be present: Web::Views::Dashboard::Index
.
-
-
-If we visit `/dashboard` we should see `Dashboard ` in our browser.
-
-### Bypass Rendering
-
-By default an action takes care of the HTTP status code and response header, but not of the body of the response.
-As seen above, it delegates the corresponding view to render and set this value.
-
-Sometimes we want to bypass this process.
-For instance we want to return a simple body like `OK`.
-To involve a view in this case is a waste of CPU cycles.
-
-If we set the body of the response from an action, **our application will ignore the view**.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- self.body = 'OK'
- end
- end
-end
-```
-
-Here is how Hanami handles an incoming request in this case:
-
- 1. The router creates a new instance of `Web::Controllers::Dashboard::Index` and invokes `#call`.
- 2. The application detects that a body is already set and doesn't instantiate the view.
- 3. The application returns the response to the browser.
-
-If we visit `/dashboard` again, now we should see `OK`.
-
-
- If the response body was already set by an action, the rendering process is bypassed.
-
-
-With direct body assignment, **we can safely delete the corresponding view and template**.
-
-## Initialization
-
-Actions are instantiated for us by Hanami at the runtime: for each incoming request, we'll automatically get a new instance.
-Because actions are objects, **we can take control on their initialization** and eventually [_inject_ our dependencies](http://en.wikipedia.org/wiki/Dependency_injection).
-This is a really useful technique for unit testing our actions.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def initialize(greeting: Greeting.new)
- @greeting = greeting
- end
-
- def call(params)
- self.body = @greeting.message
- end
- end
-end
-```
-
-There is a limitation that we should always be kept in mind:
-
-
- Action initializer MUST have an arity of 0.
-
-
-The following initializers are valid:
-
-```ruby
-# no arguments
-def initialize
- # ...
-end
-
-# default arguments
-def initialize(greeting = Greeting.new)
- # ...
-end
-
-# keyword arguments
-def initialize(greeting: Greeting.new)
- # ...
-end
-
-# options
-def initialize(options = {})
- # ...
-end
-
-# options
-def initialize(**options)
- # ...
-end
-
-# splat arguments
-def initialize(*args)
- # ...
-end
-```
diff --git a/source/guides/1.1/actions/control-flow.md b/source/guides/1.1/actions/control-flow.md
deleted file mode 100644
index efbbb1ed8..000000000
--- a/source/guides/1.1/actions/control-flow.md
+++ /dev/null
@@ -1,262 +0,0 @@
----
-title: Guides - Action Control Flow
-version: 1.1
----
-
-# Control Flow
-
-## Callbacks
-
-If we want to execute some logic before and/or after `#call` is executed, we can use a callback.
-Callbacks are useful to declutter code for common tasks like checking if a user is signed in, set a record, handle 404 responses or tidy up the response.
-
-The corresponding DSL methods are `before` and `after`.
-These methods each accept a symbol that is the name of the method that we want to call, or an anonymous proc.
-
-### Methods
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before :track_remote_ip
-
- def call(params)
- # ...
- end
-
- private
- def track_remote_ip
- @remote_ip = request.ip
- # ...
- end
- end
-end
-```
-
-With the code above, we are tracking the remote IP address for analytics purposes.
-Because it isn't strictly related to our business logic, we move it to a callback.
-
-A callback method can optionally accept an argument: `params`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before :validate_params
-
- def call(params)
- # ...
- end
-
- private
- def validate_params(params)
- # ...
- end
- end
-end
-```
-
-### Proc
-
-The examples above can be rewritten with anonymous procs.
-They are bound to the instance context of the action.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before { @remote_ip = request.ip }
-
- def call(params)
- # @remote_ip is available here
- # ...
- end
- end
-end
-```
-
-A callback proc can bound an optional argument: `params`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before {|params| params.valid? }
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-
-Don't use callbacks for model domain logic operations like sending emails.
-This is an antipattern that causes a lot of problems for code maintenance, testability and accidental side effects.
-
-
-## Halt
-
-Using exceptions for control flow is expensive for the Ruby VM.
-There is a lightweight alternative that our language supports: **signals** (see `throw` and `catch`).
-
-Hanami takes advantage of this mechanism to provide **faster control flow** in our actions via `#halt`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- halt 401 unless authenticated?
- # ...
- end
-
- private
- def authenticated?
- # ...
- end
- end
-end
-```
-
-When used, this API **interrupts the flow**, and returns the control to the framework.
-Subsequent instructions will be entirely skipped.
-
-
-When halt
is used, the flow is interrupted and the control is passed back to the framework.
-
-
-That means that `halt` can be used to skip `#call` invocation entirely if we use it in a `before` callback.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- before :authenticate!
-
- def call(params)
- # ...
- end
-
- private
- def authenticate!
- halt 401 if current_user.nil?
- end
- end
-end
-```
-
-`#halt` accepts an HTTP status code as the first argument.
-When used like this, the body of the response will be set with the corresponding message (eg. "Unauthorized" for `401`).
-
-An optional second argument can be passed to set a custom body.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- halt 404, "These aren't the droids you're looking for"
- end
- end
-end
-```
-
-When `#halt` is used, **Hanami** renders a default status page with the HTTP status and the message.
-
-
-
-To customize the UI for the HTTP 404 error, you can use a [custom error page](/guides/1.1/views/custom-error-pages).
-
-## HTTP Status
-
-In case you want let the view to handle the error, instead of using `#halt`, you should use `#status=`.
-
-The typical case is a **failed form submission**: we want to return a non-successful HTTP status (`422`) and let the view to render the form again and show the validation errors.
-
-```ruby
-# apps/web/controllers/books/create.rb
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- params do
- required(:title).filled(:str?)
- end
-
- def call(params)
- if params.valid?
- # persist
- else
- self.status = 422
- end
- end
- end
-end
-```
-
-```ruby
-# apps/web/views/books/create.rb
-module Web::Views::Books
- class Create
- include Web::View
- template 'books/new'
- end
-end
-```
-
-```erb
-# apps/web/templates/books/new.html.erb
-<% unless params.valid? %>
-
- <% params.error_messages.each do |error| %>
- <%= error %>
- <% end %>
-
-<% end %>
-
-
-```
-
-## Redirect
-
-A special case of control flow management is relative to HTTP redirect.
-If we want to reroute a request to another resource we can use `redirect_to`.
-
-When `redirect_to` is invoked, control flow is stopped and **subsequent code in the action is not executed**.
-
-It accepts a string that represents an URI, and an optional `:status` argument.
-By default the status is set to `302`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- redirect_to routes.root_path
- foo('bar') # This line will never be executed
- end
- end
-end
-```
-
-### Back
-
-Sometimes you'll want to `redirect_to` back in your browser's history so the easy way to do it
-is the following way:
-
-```ruby
-redirect_to request.get_header("Referer") || fallback_url
-```
diff --git a/source/guides/1.1/actions/cookies.md b/source/guides/1.1/actions/cookies.md
deleted file mode 100644
index ee2a96e4a..000000000
--- a/source/guides/1.1/actions/cookies.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: Guides - Action Cookies
-version: 1.1
----
-
-# Cookies
-
-## Enable Cookies
-
-Hanami applies _"batteries included, but not installed"_ philosophy.
-Cookies are a feature that is present but needs to be activated.
-
-In our application settings there is a line to uncomment.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- cookies true
- end
- end
-end
-```
-
-From now on, cookies are automatically sent for each response.
-
-### Settings
-
-With that configuration we can specify options that will be set for all cookies we send from our application.
-
- * `:domain` - `String` (`nil` by default), the domain
- * `:path` - `String` (`nil` by default), a relative URL
- * `:max_age` - `Integer` (`nil` by default), cookie duration expressed in seconds
- * `:secure` - `Boolean` (`true` by default if using SSL), restrict cookies to secure connections
- * `:httponly` - `Boolean` (`true` by default), restrict JavaScript access to cookies
-
-## Usage
-
-Cookies behave like a Hash: we can read, assign and remove values.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- cookies[:b] # read
- cookies[:a] = 'foo' # assign
- cookies[:c] = nil # remove
- cookies[:d] = { value: 'foo', path: '/bar' } # assign with options
- end
- end
-end
-```
-
-When setting a value, a cookie can accept a `String` or a `Hash` to specify inline options.
-General settings are applied automatically but these options can be used to override values case by case.
-
-### Example
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- cookies max_age: 300 # 5 minutes
- end
- end
-end
-```
-
-We're going to set two cookies from the action: the first will inherit application configuration, while the second overrides the default value.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- # Set-Cookie:a=foo; max-age=300; HttpOnly
- cookies[:a] = 'foo'
-
- # Set-Cookie:b=bar; max-age=100; HttpOnly
- cookies[:b] = { value: 'bar', max_age: 100 }
- end
- end
-end
-```
diff --git a/source/guides/1.1/actions/exception-handling.md b/source/guides/1.1/actions/exception-handling.md
deleted file mode 100644
index 4bd02e8a8..000000000
--- a/source/guides/1.1/actions/exception-handling.md
+++ /dev/null
@@ -1,93 +0,0 @@
----
-title: Guides - Action Exception Handling
-version: 1.1
----
-
-# Exception Handling
-
-Actions have an elegant API for exception handling.
-The behavior changes according to the current Hanami environment and the custom settings in our configuration.
-
-## Default Behavior
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- raise 'boom'
- end
- end
-end
-```
-
-Exceptions are automatically caught when in production mode, but not in development.
-In production, for our example, the application returns a `500` (Internal Server Error); in development, we'll see the stack trace and all the information to debug the code.
-
-This behavior can be changed with the `handle_exceptions` setting in `apps/web/application.rb`.
-
-## Custom HTTP Status
-
-If we want to map an exception to a specific HTTP status code, we can use `handle_exception` DSL.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- handle_exception ArgumentError => 400
-
- def call(params)
- raise ArgumentError
- end
- end
-end
-```
-
-`handle_exception` accepts a Hash where the key is the exception to handle, and the value is the corresponding HTTP status code.
-In our example, when `ArgumentError` is raised, it will be handled as a `400` (Bad Request).
-
-## Custom Handlers
-
-If the mapping with a custom HTTP status doesn't fit our needs, we can specify a custom handler and manage the exception by ourselves.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class PermissionDenied < StandardError
- def initialize(role)
- super "You must be admin, but you are: #{ role }"
- end
- end
-
- class Index
- include Web::Action
- handle_exception PermissionDenied => :handle_permission_error
-
- def call(params)
- unless current_user.admin?
- raise PermissionDenied.new(current_user.role)
- end
-
- # ...
- end
-
- private
- def handle_permission_error(exception)
- status 403, exception.message
- end
- end
-end
-```
-
-If we specify the name of a method (as a symbol) as the value for `handle_exception`, this method will be used to respond to the exception.
-In the example above we want to protect the action from unwanted access: only admins are allowed.
-
-When a `PermissionDenied` exception is raised it will be handled by `:handle_permission_error`.
-It MUST accept an `exception` argument—the exception instance raised inside `#call`.
-
-
-When specifying a custom exception handler, it MUST accept an exception
argument.
-
diff --git a/source/guides/1.1/actions/exposures.md b/source/guides/1.1/actions/exposures.md
deleted file mode 100644
index ac80b5491..000000000
--- a/source/guides/1.1/actions/exposures.md
+++ /dev/null
@@ -1,45 +0,0 @@
----
-title: Guides - Action Exposures
-version: 1.1
----
-
-# Exposures
-
-For complex use cases we may want to pass data to views in order to present it to our users.
-Hanami puts emphasis on explicitness: data isn't shared between the controller action and the view unless we tell it to do so.
-
-We use a simple and powerful mechanism to achieve our goal: _**exposures**_.
-Exposures create a _getter_ on the action for the given name(s) and only the whitelisted instance variables are made available to the corresponding view.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- expose :greeting
-
- def call(params)
- @greeting = "Hello"
- @foo = 23
- end
- end
-end
-```
-
-In the example above we have exposed `:greeting`, but not `:foo`.
-Only `greeting` can be used from the view and template.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
-
- def welcome_message
- greeting + " and welcome"
- end
- end
-end
-```
-
-If we try to use `foo`, Ruby will raise a `NoMethodError`.
diff --git a/source/guides/1.1/actions/http-caching.md b/source/guides/1.1/actions/http-caching.md
deleted file mode 100644
index 3689b5581..000000000
--- a/source/guides/1.1/actions/http-caching.md
+++ /dev/null
@@ -1,140 +0,0 @@
----
-title: Guides - Action HTTP Caching
-version: 1.1
----
-
-# HTTP Caching
-
-We refer to HTTP caching as the set of techniques for HTTP 1.1 and implemented by browser vendors in order to make faster interactions with the server.
-There are a few headers that, if sent, will enable these HTTP caching mechanisms.
-
-## Cache Control
-
-Actions offer a DSL to set a special header `Cache-Control`.
-The first argument is a cache response directive like `:public` or `"must-revalidate"`, while the second argument is a set of options like `:max_age`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- include Hanami::Action::Cache
-
- cache_control :public, max_age: 600
- # => Cache-Control: public, max-age: 600
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-## Expires
-
-Another HTTP caching special header is `Expires`.
-It can be used for retrocompatibility with old browsers which don't understand `Cache-Control`.
-
-Hanami's solution for _expire_ combines support for all the browsers by sending both the headers.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- include Hanami::Action::Cache
- expires 60, :public, max_age: 300
- # => Expires: Mon, 18 May 2015 09:19:18 GMT
- # Cache-Control: public, max-age: 300
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-## Conditional GET
-
-_Conditional GET_ is a two step workflow to inform browsers that a resource hasn't changed since the last visit.
-At the end of the first request, the response includes special HTTP response headers that the browser will use next time it comes back.
-If the header matches the value that the server calculates, then the resource is still cached and a `304` status (Not Modified) is returned.
-
-### ETag
-
-The first way to match a resource freshness is to use an identifier (usually an MD5 token).
-Let's specify it with `fresh etag:`.
-
-If the given identifier does NOT match the `If-None-Match` request header, the request will return a `200` with an `ETag` response header with that value.
-If the header does match, the action will be halted and a `304` will be returned.
-
-```ruby
-# apps/web/controllers/users/show.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Users
- class Show
- include Web::Action
- include Hanami::Action::Cache
-
- def call(params)
- @user = UserRepository.new.find(params[:id])
- fresh etag: etag
-
- # ...
- end
-
- private
-
- def etag
- "#{ @user.id }-#{ @user.updated_at }"
- end
- end
-end
-
-# Case 1 (missing or non-matching If-None-Match)
-# GET /users/23
-# => 200, ETag: 84e037c89f8d55442366c4492baddeae
-
-# Case 2 (matching If-None-Match)
-# GET /users/23, If-None-Match: 84e037c89f8d55442366c4492baddeae
-# => 304
-```
-
-### Last Modified
-
-The second way is to use a timestamp via `fresh last_modified:`.
-
-If the given timestamp does NOT match `If-Modified-Since` request header, it will return a `200` and set the `Last-Modified` response header with the timestamp value.
-If the timestamp does match, the action will be halted and a `304` will be returned.
-
-```ruby
-# apps/web/controllers/users/show.rb
-require 'hanami/action/cache'
-
-module Web::Controllers::Users
- class Show
- include Web::Action
- include Hanami::Action::Cache
-
- def call(params)
- @user = UserRepository.new.find(params[:id])
- fresh last_modified: @user.updated_at
-
- # ...
- end
- end
-end
-
-# Case 1 (missing or non-matching Last-Modified)
-# GET /users/23
-# => 200, Last-Modified: Mon, 18 May 2015 10:04:30 GMT
-
-# Case 2 (matching Last-Modified)
-# GET /users/23, If-Modified-Since: Mon, 18 May 2015 10:04:30 GMT
-# => 304
-```
diff --git a/source/guides/1.1/actions/mime-types.md b/source/guides/1.1/actions/mime-types.md
deleted file mode 100644
index eac483f4a..000000000
--- a/source/guides/1.1/actions/mime-types.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: Guides - Action MIME Types
-version: 1.1
----
-
-# MIME Types
-
-Actions have advanced features for MIME type detection, automatic headers, whitelisting etc..
-
-## Request Introspection
-
-In order to understand what the requested MIME type is, an action looks at the `Accept` request header and exposes a high level API: `#format` and `#accept?`.
-
-The first returns a symbol representation of the MIME type (eg. `:html`, `:json`, `:xml` etc..), while the second is a query method that accepts a MIME type string and checks if it's accepted by the current browser.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- puts format # => :html
-
- puts accept?('text/html') # => true
- puts accept?('application/png') # => false
- end
- end
-end
-```
-
-## Automatic Content-Type
-
-An action returns the `Content-Type` response header automatically according to the requested MIME Type and charset.
-
-If the client asks for `Accept: text/html,application/xhtml+xml,application/xml;q=0.9`, the action will return `Content-Type: text/html; charset=utf-8`.
-
-### Default Request Format
-
-If a client asks for a generic `Accept: */*`, the action will fall back to the **application default format**.
-This is a setting that allows us to safely handle cases like our example; the default value is `:html`.
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- default_request_format :json
- end
- end
-end
-```
-
-### Default Response Format
-
-If we are building a JSON API app, it can be useful to specify a `:json` as default MIME Type for the response.
-The default value is `:html`.
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- default_response_format :json
- end
- end
-end
-```
-
-### Default Charset
-
-Similarly, we can specify a different default charset to return.
-The standard value is `utf-8`, but we can change it in our settings.
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- default_charset 'koi8-r'
- end
- end
-end
-```
-
-### Override
-
-There is a way we can force the returned `Content-Type`: use `#format=`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- puts self.format # => :html
-
- # force a different value
- self.format = :json
- puts self.format # => :json
- end
- end
-end
-```
-
-The example above will return `Content-Type: application/json; charset=utf-8`.
-
-## Whitelisting
-
-We can also restrict the range of accepted MIME Types.
-If the incoming request doesn't satisfy this constraint, the application will return a `Not Acceptable` status (`406`).
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- accept :html, :json
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-## Register MIME Types
-
-Hanami knows about more than 100 of the most common MIME types.
-However, we may want to add custom types in order to use them with `#format=` or `.accept`.
-
-In our application settings we can use `controller.format`, which accepts a Hash where the key is the format symbol (`:custom`) and the value is a string expressed in the MIME type standard (`application/custom`).
-
-```ruby
-# apps/web/application.rb
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- controller.format custom: 'application/custom'
- end
- end
-end
-```
diff --git a/source/guides/1.1/actions/overview.md b/source/guides/1.1/actions/overview.md
deleted file mode 100644
index 24988bacb..000000000
--- a/source/guides/1.1/actions/overview.md
+++ /dev/null
@@ -1,88 +0,0 @@
----
-title: Guides - Actions Overview
-version: 1.1
----
-
-# Overview
-
-An action is an endpoint that handles incoming HTTP requests for a specific [route](/guides/1.1/routing/overview).
-In a Hanami application, an **action is an object**, while a **controller is a Ruby module** that groups them.
-
-This design provides self contained actions that don't share their context accidentally with other actions. It also prevents gigantic controllers.
-It has several advantages in terms of testability and control of an action.
-
-## A Simple Action
-
-Hanami ships with a generator for actions. Let's create a new one:
-
-```shell
-hanami generate action web dashboard#index
-```
-
-Let's examine the action:
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- end
- end
-end
-```
-
-### Naming
-
-That file begins with a module declaration.
-
-The first token is the name of our application: `Web`.
-Hanami can run multiple applications within the same Ruby process.
-They are located under `apps/`.
-Their name is used as a **top-level module to contain inner components** like actions and views, in order to **avoid naming collisions**.
-If we have another action `Home::Index` under an application `Admin`, the two of them can coexist inside the same codebase.
-
-The second token is a conventional name: `Controllers`.
-**All the controllers are nested under it.**
-This module is generated at runtime for us, when the application starts.
-
-
- For a given application named Web
, controllers are available under Web::Controllers
.
-
-
-The last bit is `Dashboard`, which is our controller.
-
-The whole action name is `Web::Controllers::Dashboard::Index`.
-
-
- You should avoid giving your action modules the same name as your application, e.g. avoid naming a controller Web
in an app named Web
. If you have a controller name like Web::Controllers::Web
then some code across your app will break with errors about constants not being found, for example in views which include Web::Layout
. This is because Ruby starts constant lookup with the current module, so a constant like Web::Layout
referenced by code in the Web::Controllers::Web
or Web::Controllers::Web::MyAction
module will be converted to Web::Controllers::Web::Layout
, which can't be found and causes a constant lookup error.
-
-
- If you absolutely must name a controller with the same name as your application, you'll need to explicitly set the namespace lookup for things which should be included from immediately under the app, not the controller by prefixing those names with ::
, e.g. change your views to include ::Web::Layout
instead of include Web::Layout
, and using include ::Web::Action
in your controllers.
-
-
-###Β Action Module
-
-Hanami philosophy emphasizes _composition over inheritance_ and avoids the [framework superclass antipattern](http://michaelfeathers.typepad.com/michael_feathers_blog/2013/01/the-framework-superclass-anti-pattern.html).
-For this reason, all the components are provided as **modules to include** instead of base classes to inherit from.
-
-Like we said before, Hanami can run multiple apps within the same Ruby process.
-Each of them has its own configuration.
-To keep separated actions from an application named `Web` and an application named `Admin`, we include `Web::Action` and `Admin::Action` respectively.
-
-In our example, we have a directive `include Web::Action`.
-That means our action will behave according to the configuration of the `Web` application.
-
-
- For a given application named Web
, the action mixin to include is Web::Action
.
-
-
-### Interface
-
-When we include `Web::Action`, we made our object compliant with [Hanami::Controller](https://github.com/hanami/controller)'s actions.
-We need to implement `#call`, which is a method that accepts only one argument: `params`.
-That is the object that carries the payload that comes from incoming HTTP requests from the [router](/guides/1.1/routing/basic-usage).
-
-This interface reminds us of Rack.
-Indeed, our action is compatible with the Rack protocol.
diff --git a/source/guides/1.1/actions/parameters.md b/source/guides/1.1/actions/parameters.md
deleted file mode 100644
index 04e7e7366..000000000
--- a/source/guides/1.1/actions/parameters.md
+++ /dev/null
@@ -1,333 +0,0 @@
----
-title: Guides - Action Parameters
-version: 1.1
----
-
-# Parameters
-
-Parameters are taken from the Rack env and passed as an argument to `#call`.
-They are similar to a Ruby Hash, but they offer an expanded set of features.
-
-## Sources
-
-Params can come from:
-
- * [Router variables](/guides/1.1/routing/basic-usage) (eg. `/books/:id`)
- * Query string (eg. `/books?title=Hanami`)
- * Request body (eg. a `POST` request to `/books`)
-
-## Access
-
-To access the value of a param, we can use the _subscriber operator_ `#[]`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- self.body = "Query string: #{ params[:q] }"
- end
- end
-end
-```
-
-If we visit `/dashboard?q=foo`, we should see `Query string: foo`.
-
-### Symbol Access
-
-Params and nested params can be referenced **only** via symbols.
-
-```ruby
-params[:q]
-params[:book][:title]
-```
-
-Now, what happens if the parameter `:book` is missing from the request?
-Because `params[:book]` is `nil`, we can't access `:title`.
-In this case Ruby will raise a `NoMethodError`.
-
-We have a safe solution for our problem: `#get`.
-It accepts a list of symbols, where each symbol represents a level in our nested structure.
-
-```ruby
-params.get(:book, :title) # => "Hanami"
-params.get(:unknown, :nested, :param) # => nil instead of NoMethodError
-```
-
-## Whitelisting
-
-In order to show how whitelisting works, let's create a new action:
-
-```shell
-bundle exec hanami generate action web signup#create
-```
-
-We want to provide self-registration for our users.
-We build a HTML form which posts to an action that accepts the payload and stores it in the `users` table.
-That table has a boolean column `admin` to indicate whether a person has administration permissions.
-
-A malicious user can exploit this scenario by sending this extra parameter to our application, thereby making themselves an administrator.
-
-We can easily fix this problem by filtering the allowed parameters that are permitted inside our application.
-Please always remember that **params represent untrusted input**.
-
-We use `.params` to map the structure of the (nested) parameters.
-
-```ruby
-# apps/web/controllers/signup/create.rb
-module Web::Controllers::Signup
- class Create
- include Web::Action
-
- params do
- required(:email).filled
- required(:password).filled
-
- required(:address).schema do
- required(:country).filled
- end
- end
-
- def call(params)
- puts params[:email] # => "alice@example.org"
- puts params[:password] # => "secret"
- puts params[:address][:country] # => "Italy"
-
- puts params[:admin] # => nil
- end
- end
-end
-```
-
-Even if `admin` is sent inside the body of the request, it isn't accessible from `params`.
-
-## Validations & Coercion
-
-### Use Cases
-
-In our example (called _"Signup"_), we want to make `password` a required param.
-
-Imagine we introduce a second feature: _"Invitations"_.
-An existing user can ask someone to join.
-Because the invitee will decide a password later on, we want to persist that `User` record without that value.
-
-If we put `password` validation in `User`, we need to handle these two use cases with a conditional.
-But in the long term this approach is painful from a maintenance perspective.
-
-```ruby
-# Example of poor style for validations
-class User
- attribute :password, presence: { if: :password_required? }
-
- private
- def password_required?
- !invited_user? && !admin_password_reset?
- end
-end
-```
-
-We can see validations as the set of rules for data correctness that we want for **a specific use case**.
-For us, a `User` can be persisted with or without a password, **depending on the workflow** and the route through
-which the `User` is persisted.
-
-### Boundaries
-
-The second important aspect is that we use validations to prevent invalid inputs to propagate in our system.
-In an MVC architecture, the model layer is the **farthest** from the input.
-It's expensive to check the data right before we create a record in the database.
-
-If we **consider correct data as a precondition** before starting our workflow, we should stop unacceptable inputs as soon as possible.
-
-Think of the following method.
-We don't want to continue if the data is invalid.
-
-```ruby
-def expensive_computation(argument)
- return if argument.nil?
- # ...
-end
-```
-
-### Usage
-
-We can coerce the Ruby type, validate if a param is required, determine if it is within a range of values, etc..
-
-```ruby
-# apps/web/controllers/signup/create.rb
-module Web::Controllers::Signup
- class Create
- include Web::Action
- MEGABYTE = 1024 ** 2
-
- params do
- required(:name).filled(:str?)
- required(:email).filled(:str?, format?: /@/).confirmation
- required(:password).filled(:str?).confirmation
- required(:terms_of_service).filled(:bool?)
- required(:age).filled(:int?, included_in?: 18..99)
- optional(:avatar).filled(size?: 1..(MEGABYTE * 3))
- end
-
- def call(params)
- if params.valid?
- # ...
- else
- # ...
- end
- end
- end
-end
-```
-
-Parameter validations are delegated, under the hood, to [Hanami::Validations](https://github.com/hanami/validations).
-Please check the related documentation for a complete list of options and how to share code between validations.
-
-## Concrete Classes
-
-The params DSL is really quick and intuitive but it has the drawback that it can be visually noisy and makes it hard to unit test.
-An alternative is to extract a class and pass it as an argument to `.params`.
-
-```ruby
-# apps/web/controllers/signup/my_params.rb
-module Web::Controllers::Signup
- class MyParams < Web::Action::Params
- MEGABYTE = 1024 ** 2
-
- params do
- required(:name).filled(:str?)
- required(:email).filled(:str?, format?: /@/).confirmation
- required(:password).filled(:str?).confirmation
- required(:terms_of_service).filled(:bool?)
- required(:age).filled(:int?, included_in?: 18..99)
- optional(:avatar).filled(size?: 1..(MEGABYTE * 3)
- end
- end
-end
-```
-
-```ruby
-# apps/web/controllers/signup/create.rb
-require_relative './my_params'
-
-module Web::Controllers::Signup
- class Create
- include Web::Action
- params MyParams
-
- def call(params)
- if params.valid?
- # ...
- else
- # ...
- end
- end
- end
-end
-```
-
-### Inline predicates
-
-In case there is a predicate that is needed only for the current params, you can define inline predicates:
-
-```ruby
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- params Class.new(Hanami::Action::Params) {
- predicate(:cool?, message: "is not cool") do |current|
- current.match(/cool/)
- end
-
- validations do
- required(:book).schema do
- required(:title) { filled? & str? & cool? }
- end
- end
- }
-
- def call(params)
- if params.valid?
- self.body = 'OK'
- else
- self.body = params.error_messages.join("\n")
- end
- end
- end
-end
-```
-
-## Body Parsers
-
-Rack ignores request bodies unless they come from a form submission.
-If we have a JSON endpoint, the payload isn't available in `params`.
-
-```ruby
-module Web::Controllers::Books
- class Create
- include Web::Action
- accept :json
-
- def call(params)
- puts params.to_h # => {}
- end
- end
-end
-```
-
-```shell
-curl http://localhost:2300/books \
- -H "Content-Type: application/json" \
- -H "Accept: application/json" \
- -d '{"book":{"title":"Hanami"}}' \
- -X POST
-```
-
-In order to make book payload available in `params`, we should enable this feature:
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- body_parsers :json
- end
- end
-end
-```
-
-Now `params.get(:book, :title)` returns `"Hanami"`.
-
-In case there is no suitable body parser for your format in Hanami, it is possible to declare a new one:
-
-```ruby
-# lib/foo_parser.rb
-class FooParser
- def mime_types
- ['application/foo']
- end
-
- def parse(body)
- # manually parse body
- end
-end
-```
-
-and subsequently register it:
-
-```ruby
-# apps/web/application.rb
-# ...
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- body_parsers FooParser.new
- # ...
- end
- end
-end
-```
diff --git a/source/guides/1.1/actions/rack-integration.md b/source/guides/1.1/actions/rack-integration.md
deleted file mode 100644
index c2b5c9752..000000000
--- a/source/guides/1.1/actions/rack-integration.md
+++ /dev/null
@@ -1,91 +0,0 @@
----
-title: Guides - Request & Response
-version: 1.1
----
-
-# Rack Integration
-
-## Rack Environment
-
-Actions offer a high level API built on top of Rack.
-If we need to access raw data from Rack environment we can use `params.env`.
-
-## Rack Middleware
-
-Hanami mounts a very thin default middleware stack.
-Additional components can be mounted globally, at the application level, or locally.
-
-### Global Middleware
-
-If we need a component that wraps all the applications (under `apps/`), we can edit `config.ru` at the root of the project.
-
-```ruby
-# config.ru
-require './config/environment'
-require 'rack/auth/basic'
-
-use Rack::Auth::Basic
-run Hanami.app
-```
-
-### Application Middleware
-
-If we need a component that's only used by a specific application (under `apps/`), we can add it to the application's configuration.
-
-```ruby
-# apps/web/application.rb
-require 'rack/auth/basic'
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- middleware.use Rack::Auth::Basic
- end
- end
-end
-```
-
-### Action Middleware
-
-Sometimes we need a middleware only to be used for a set of well known resources.
-If we mount it at the global or application level the performance will start to degrade.
-Actions allow us to mount a fine grained middleware stack.
-
-```ruby
-# apps/web/controllers/sessions/create.rb
-require 'omniauth'
-
-module Web::Controllers::Sessions
- class Create
- include Web::Action
-
- use OmniAuth::Builder {
- # ...
- }
-
- def call(params)
- # ...
- end
- end
-end
-```
-
-We can use the following syntax to mount different middleware that require arguments.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- use XMiddleware.new('x', 123)
- use YMiddleware.new
- use ZMiddleware
-
- def call(params)
- # ...
- end
- end
-end
-```
diff --git a/source/guides/1.1/actions/request-and-response.md b/source/guides/1.1/actions/request-and-response.md
deleted file mode 100644
index 9f189dbaa..000000000
--- a/source/guides/1.1/actions/request-and-response.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: Guides - Request & Response
-version: 1.1
----
-
-# Request
-
-In order to access the metadata coming from a HTTP request, an action has a private object `request` that derives from `Rack::Request`.
-Here an example of some information that we can introspect.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- puts request.path_info # => "/dashboard"
- puts request.request_method # => "GET"
- puts request.get? # => true
- puts request.post? # => false
- puts request.xhr? # => false
- puts request.referer # => "http://example.com/"
- puts request.user_agent # => "Mozilla/5.0 Macintosh; ..."
- puts request.ip # => "127.0.0.1"
- end
- end
-end
-```
-
-
- Instantiating a request
for each incoming HTTP request can lead to minor performance degradation.
- As an alternative, please consider getting the same information from private action methods like accept?
or from the raw Rack environment params.env
.
-
-
-# Response
-
-The implicit return value of `#call` is a serialized `Rack::Response` (see [#finish](http://rubydoc.info/github/rack/rack/master/Rack/Response#finish-instance_method)):
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- end
- end
-end
-
-# It will return [200, {}, [""]]
-```
-
-It has private accessors to explicitly set status, headers and body:
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- self.status = 201
- self.body = 'Your resource has been created'
- self.headers.merge!({ 'X-Custom' => 'OK' })
- end
- end
-end
-
-# It will return [201, { "X-Custom" => "OK" }, ["Your resource has been created"]]
-```
-
-As shortcut we can use `#status`.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- status 201, "Your resource has been created"
- end
- end
-end
-
-# It will return [201, {}, ["Your resource has been created"]]
diff --git a/source/guides/1.1/actions/sessions.md b/source/guides/1.1/actions/sessions.md
deleted file mode 100644
index 1935d91e5..000000000
--- a/source/guides/1.1/actions/sessions.md
+++ /dev/null
@@ -1,61 +0,0 @@
----
-title: Guides - Action Sessions
-version: 1.1
----
-
-# Sessions
-
-## Enable Sessions
-
-Sessions are available in Hanami applications, but not enabled by default.
-If we want to turn on this feature, we just need to uncomment a line of code.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- sessions :cookie, secret: ENV['WEB_SESSIONS_SECRET']
- end
- end
-end
-```
-
-The first argument is the name of the adapter for the session storage.
-The default value is `:cookie`, that uses `Rack::Session::Cookie`.
-
-
-The name of the session adapter is the underscored version of the class name under Rack::Session
namespace.
-Example: :cookie
for Rack::Session::Cookie
.
-
-
-We can use a different storage compatible with Rack sessions.
-Let's say we want to use Redis. We should bundle `redis-rack` and specify the name of the adapter: `:redis`.
-Hanami is able to autoload the adapter and use it when the application is started.
-
-
-Custom storage technologies are autoloaded via require "rack/session/#{ adapter_name }"
.
-
-
-The second argument passed to `sessions` is a Hash of options that are **passed to the adapter**.
-We find only a default `:secret`, but we can specify all the values that are supported by the current adapter.
-
-## Usage
-
-Sessions behave like a Hash: we can read, assign and remove values.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
-
- def call(params)
- session[:b] # read
- session[:a] = 'foo' # assign
- session[:c] = nil # remove
- end
- end
-end
-```
diff --git a/source/guides/1.1/actions/share-code.md b/source/guides/1.1/actions/share-code.md
deleted file mode 100644
index 4ead62c7b..000000000
--- a/source/guides/1.1/actions/share-code.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-title: Guides - Action Share Code
-version: 1.1
----
-
-# Share Code
-
-Actions as objects have a lot of advantages but they make code sharing less intuitive.
-This section shares a few techniques to make this possible.
-
-## Prepare
-
-In our settings (`apps/web/application.rb`), there is a code block that allows us to share the code for **all the actions** of our application.
-When an action includes the `Web::Action` module, that block code is yielded within the context of that class.
-This is heavily inspired by Ruby Module and its `included` hook.
-
-Imagine we want to check if the current request comes from an authenticated user.
-
-We craft a module in `apps/web/controllers/authentication.rb`.
-
-```ruby
-# apps/web/controllers/authentication.rb
-module Web
- module Authentication
- def self.included(action)
- action.class_eval do
- before :authenticate!
- expose :current_user
- end
- end
-
- private
-
- def authenticate!
- halt 401 unless authenticated?
- end
-
- def authenticated?
- !!current_user
- end
-
- def current_user
- @current_user ||= UserRepository.new.find(session[:user_id])
- end
- end
-end
-```
-
-Once included by an action, it will set a [before callback](/guides/1.1/actions/control-flow) that executes `:authenticate!` for each request.
-If not logged in, a `401` is returned, otherwise the flow can go ahead and hit `#call`.
-It also exposes `current_user` for all the views (see [Exposures](/guides/1.1/actions/exposures)).
-
-It will be really tedious to include this module for all the actions of our app.
-We can use `controller.prepare` for the scope.
-
-```ruby
-# apps/web/application.rb
-require_relative './controllers/authentication'
-
-module Web
- class Application < Hanami::Application
- configure do
- controller.prepare do
- include Web::Authentication
- end
- end
- end
-end
-```
-
-
-Code included via prepare
is available for ALL the actions of an application.
-
-
-### Skipping A Callback
-
-Let's say we have included `Authentication` globally, but want to skip the execution of its callback for certain resources.
-A typical use case is to redirect unauthenticated requests to our sign in form.
-
-The solution is really simple and elegant at the same time: override that method.
-
-```ruby
-# apps/web/controllers/sessions/new.rb
-module Web::Controllers::Sessions
- class New
- include Web::Action
-
- def call(params)
- # ...
- end
-
- private
- def authenticate!
- # no-op
- end
- end
-end
-```
-
-The action will still try to invoke `:authenticate!`, because, technically speaking, **callbacks execution can't be skipped**.
-But if we override that method with an empty implementation, it does nothing and our non-signedin users can reach the wanted resource.
-
-## Module Inclusion
-
-Imagine we have a RESTful resource named `books`.
-There are several actions (`show`, `edit`, `update` and `destroy`) which need to find a specific book to perform their job.
-
-What if we want to DRY the code of all these actions?
-Ruby comes to our rescue.
-
-```ruby
-# apps/web/controllers/books/set_book.rb
-module Web::Controllers::Books
- module SetBook
- def self.included(action)
- action.class_eval do
- before :set_book
- end
- end
-
- private
-
- def set_book
- @book = BookRepository.new.find(params[:id])
- halt 404 if @book.nil?
- end
- end
-end
-```
-
-We have defined a module for our behavior to share. Let's include it in all the actions that need it.
-
-```ruby
-# apps/web/controllers/books/update.rb
-require_relative './set_book'
-
-module Web::Controllers::Books
- class Update
- include Web::Action
- include SetBook
-
- def call(params)
- # ...
- end
- end
-end
-```
-
diff --git a/source/guides/1.1/actions/testing.md b/source/guides/1.1/actions/testing.md
deleted file mode 100644
index bc0bada61..000000000
--- a/source/guides/1.1/actions/testing.md
+++ /dev/null
@@ -1,310 +0,0 @@
----
-title: Guides - Action Testing
-version: 1.1
----
-
-# Testing
-
-Hanami pays a lot of attention to code testability and it offers advanced features to make our lives easier.
-The framework supports Minitest (default) and RSpec.
-
-## Unit Tests
-
-First of all, actions can be unit tested.
-That means we can instantiate, exercise and verify expectations **directly on actions instances**.
-
-```ruby
-# spec/web/controllers/dashboard/index_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/dashboard/index'
-
-describe Web::Controllers::Dashboard::Index do
- let(:action) { Web::Controllers::Dashboard::Index.new }
- let(:params) { Hash[] }
-
- it "is successful" do
- response = action.call(params)
- response[0].must_equal 200
- end
-end
-```
-
-In the example above, `action` is an instance of `Web::Controllers::Dashboard::Index`, we can invoke `#call` on it, passing a Hash of parameters.
-The [implicit returning value](/guides/1.1/actions/rack-integration) is a serialized Rack response.
-We're asserting that the status code (`response[0]`) is successful (equals to `200`).
-
-### Running Tests
-
-We can run the entire test suite or a single file.
-
-The default Rake task for the application serves for our first case: `bundle exec rake`.
-All the dependencies and the application code (actions, views, entities, etc..) are eagerly loaded.
-**Boot time is slow in this case.**
-
-
-The entire test suite can be run via default Rake task. It loads all the dependencies, and the application code.
-
-
-The second scenario can be done via: `ruby -Ispec spec/web/controllers/dashboard/index_spec.rb` (or `rspec spec/web/controllers/dashboard/index_spec.rb` if we use RSpec).
-When we run a single file example **only the framework and the application settings are loaded**.
-
-Please note the `require_relative` line in the example.
-It's **auto generated for us** and it's needed to load the current action under test.
-This mechanism allows us to run unit tests in **isolation**.
-**Boot time is magnitudes faster**.
-
-
-A single unit test can be run directly. It only loads the dependencies, but not the application code.
-The class under test is loaded via require_relative
, a line automatically generated for us.
-In this way we can have a faster startup time and a shorter feedback cycle.
-
-
-### Params
-
-When testing an action, we can easily simulate parameters and headers coming from the request.
-We just need to pass them as a Hash.
-Headers for Rack env such as `HTTP_ACCEPT` can be mixed with params like `:id`.
-
-The following test example uses both.
-
-```ruby
-# spec/web/controllers/users/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/show'
-
-describe Web::Controllers::Users::Show do
- let(:action) { Web::Controllers::Users::Show.new }
- let(:format) { 'application/json' }
- let(:user_id) { '23' }
-
- it "is successful" do
- response = action.call(id: user_id, 'HTTP_ACCEPT' => format)
-
- response[0].must_equal 200
- response[1]['Content-Type'].must_equal "#{ format }; charset=utf-8"
- response[2].must_equal ["ID: #{ user_id }"]
- end
-end
-```
-
-Here the corresponding production code.
-
-```ruby
-# apps/web/controllers/users/show.rb
-module Web::Controllers::Users
- class Show
- include Web::Action
-
- def call(params)
- puts params.class # => Web::Controllers::Users::Show::Params
- self.body = "ID: #{ params[:id] }"
- end
- end
-end
-```
-
-
-Simulating request params and headers is simple for Hanami actions. We pass them as a Hash
and they are transformed into an instance of Hanami::Action::Params
.
-
-
-### Exposures
-
-There are cases where we want to verify the internal state of an action.
-Imagine we have a classic user profile page, like depicted in the example above.
-The action asks for a record that corresponds to the given id, and then set a `@user` instance variable.
-How do we verify that the record is the one that we are looking for?
-
-Because we want to make `@user` available to the outside world, we're going to use an [_exposure_](/guides/1.1/actions/exposures).
-They are used to pass a data payload between an action and the corresponding view.
-When we do `expose :user`, Hanami creates a getter (`#user`), so we can easily assert if the record is the right one.
-
-```ruby
-# apps/web/controllers/users/show.rb
-module Web::Controllers::Users
- class Show
- include Web::Action
- expose :user, :foo
-
- def call(params)
- @user = UserRepository.new.find(params[:id])
- @foo = 'bar'
- end
- end
-end
-```
-
-We have used two _exposures_: `:user` and `:foo`, let's verify if they are properly set.
-
-```ruby
-# spec/web/controllers/users/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/show'
-
-describe Web::Controllers::Users::Show do
- before do
- @user = UserRepository.new.create(name: 'Luca')
- end
-
- let(:action) { Web::Controllers::Users::Show.new }
-
- it "is successful" do
- response = action.call(id: @user.id)
-
- response[0].must_equal 200
-
- action.user.must_equal @user
- action.exposures.must_equal({user: @user, foo: 'bar'})
- end
-end
-```
-
-
-The internal state of an action can be easily verified with exposures .
-
-
-### Dependency Injection
-
-During unit testing, we may want to use mocks to make tests faster or to avoid hitting external systems like databases, file system or remote services.
-Because we can instantiate actions during tests, there is no need to use testing antipatterns (eg. `any_instance_of`, or `UserRepository.new.stub(:find)`).
-Instead, we can just specify which collaborators we want to use via _dependency injection_.
-
-Let's rewrite the test above so that it does not hit the database.
-We're going to use RSpec for this example as it has a nicer API for mocks (doubles).
-
-```ruby
-# spec/web/controllers/users/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/show'
-
-RSpec.describe Web::Controllers::Users::Show do
- let(:action) { Web::Controllers::Users::Show.new(repository: repository) }
- let(:user) { User.new(id: 23, name: 'Luca') }
- let(:repository) { double('repository', find: user) }
-
- it "is successful" do
- response = action.call(id: user.id)
-
- expect(response[0]).to eq 200
- expect(action.user).to eq user
- expect(action.exposures).to eq({user: user})
- end
-end
-```
-
-We have injected the repository dependency which is a mock in our case.
-Here how to adapt our action.
-
-```ruby
-# apps/web/controllers/users/show.rb
-module Web::Controllers::Users
- class Show
- include Web::Action
- expose :user
-
- def initialize(repository: UserRepository.new)
- @repository = repository
- end
-
- def call(params)
- @user = @repository.find(params[:id])
- end
- end
-end
-```
-
-
-Please be careful using doubles in unit tests. Always verify that the mocks are in a true representation of the corresponding production code.
-
-
-
-### Flash messages
-
-In your action tests, you can check `flash` messages too. For this, you can use `exposures` method for getting all flash data.
-
-The following test example uses this method.
-
-```ruby
-# spec/web/controllers/users/create_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/controllers/users/create'
-
-describe Web::Controllers::Users::Create do
- let(:action) { Web::Controllers::Users::Create.new }
- let(:user_params) { name: 'Luca' }
-
- it "is successful" do
- response = action.call(id: user_params)
- flash = action.exposures[:flash]
-
- flash[:info].must_equal 'User was successfully created'
- end
-end
-```
-
-## Requests Tests
-
-Unit tests are a great tool to assert that low level interfaces work as expected.
-We always advise combining them with integration tests.
-
-In the case of Hanami web applications, we can write features (aka acceptance tests) with Capybara, but what do we use when we are building HTTP APIs?
-The tool that we suggest is `rack-test`.
-
-Imagine we have an API application mounted at `/api/v1` in our `Hanami::Container`.
-
-```ruby
-# config/environment.rb
-# ...
-Hanami::Container.configure do
- mount ApiV1::Application, at: '/api/v1'
- mount Web::Application, at: '/'
-end
-```
-
-Then we have the following action.
-
-```ruby
-# apps/api_v1/controllers/users/show.rb
-module ApiV1::Controllers::Users
- class Show
- include ApiV1::Action
- accept :json
-
- def call(params)
- user = UserRepository.new.find(params[:id])
- self.body = JSON.generate(user.to_h)
- end
- end
-end
-```
-
-In this case we don't care too much about the internal state of the action, but about the output visible to the external world.
-This is why we haven't set `user` as an instance variable and why we haven't exposed it.
-
-```ruby
-# spec/api_v1/requests/users_spec.rb
-require 'spec_helper'
-
-describe "API V1 users" do
- include Rack::Test::Methods
-
- before do
- @user = UserRepository.new.create(name: 'Luca')
- end
-
- # app is required by Rack::Test
- def app
- Hanami.app
- end
-
- it "is successful" do
- get "/api/v1/users/#{ @user.id }"
-
- last_response.must_be :ok?
- last_response.body.must_equal(JSON.generate(@user.to_h))
- end
-end
-```
-
-
-Please avoid test doubles when writing full integration tests, as we want to verify that the whole stack is behaving as expected.
-
diff --git a/source/guides/1.1/architecture/interactors.md b/source/guides/1.1/architecture/interactors.md
deleted file mode 100644
index 155400433..000000000
--- a/source/guides/1.1/architecture/interactors.md
+++ /dev/null
@@ -1,518 +0,0 @@
----
-title: Architecture - Interactors
-version: 1.1
----
-
-# Overview
-Hanami provides an **optional** tool for organizing your code.
-
-These are *Interactors*,
-also referred to *service objects*, *use-cases* or *operations*
-
-We think they're great and help manage complexity,
-but you're free to build a Hanami app without them at all.
-
-In this guide, we'll explain how Hanami's Interactors work by adding a small feature to an existing application.
-
-The existing application we'll work from is the `bookshelf` application
-from the [Getting Started Guide](/guides/getting-started).
-
-# A New Feature: Email Notifications
-The story for our new feature is:
-> As an administrator, I want to receive an email notification when a book is added
-
-Since the application doesn't have authentication, anyone can add a new book.
-We'll provide an admin email address via an environment variable.
-
-This is just an example to show when you should use an Interactor, and,
-specifically, how `Hanami::Interactor` can be used.
-
-This example could provide a basis for other features like
-adding administrator approval of new books before they're posted,
-or allowing users to provide an email address, then edit the book via a special link.
-
-In practice,
-you can use `Interactors` to implement *any business logic*.
-It's particularly useful for when you want to do several things at once,
-in order to manage the complexity of the codebase.
-
-They're used to isolate non-trivial business logic.
-This follows the [Single Responsibility Principle](https://en.wikipedia.org/wiki/Single_responsibility_principle)
-
-In a web application, they will generally be called from the controller action.
-This lets you separate concerns.
-Your business logic objects, Interactors, won't know about the web at all.
-
-# Callbacks? We Don't Need No Stinkin' Callbacks!
-An easy way of implementing email notification would be to add a callback.
-
-That is: after a new `Book` record is created in the database, an email is sent out.
-
-By design, Hanami doesn't provide any such mechanism.
-This is because we consider persistence callbacks an **anti-pattern**.
-They violate the Single Responsibility principle.
-In this case, they improperly mix persistence with email notifications.
-
-During testing (and at some other point, most likely),
-you'll want to skip that callback.
-This quickly becomes confusing,
-since multiple callbacks on the same event will be triggered in a specific order.
-Also, you may want to skip several callbacks at some point.
-They make code hard to understand, and brittle.
-
-Instead, we recommend being **explicit over implicit**.
-
-An Interactor is an object that represents a specific *use-case*.
-
-They let each class have a single responsibility.
-An Interactor's single responsibility is to combine object and method calls in order to achieve a specific outcome.
-
-We provide `Hanami::Interactor` as a module,
-so you can start with a Plain Old Ruby Object,
-and include `include Hanami::Interactor` when you need some of its features.
-
-# Concept
-
-The central idea behind Interactors is that you extract an isolated piece of functionality into a new class.
-
-You should only write two public methods: `initialize` and `call`.
-
-This means objects are easy to reason about,
-since there's only one possible method to call after the object is created.
-
-By encapsulating behavior into a single object, it's easier to test.
-It also makes your codebase easier to understand,
-rather than leaving your complexity hidden, only expressed implicitly.
-
-# Preparing
-Let's say we have our `bookshelf` application,
-from the [Getting Started](/guides/getting-started)
-and we want to add the 'email notification for added book' feature.
-
-# Creating Our Interactor
-Let's create a folder for our Interactors, and a folder for their specs:
-
-```shell
-% mkdir lib/bookshelf/interactors
-% mkdir spec/bookshelf/interactors
-```
-We put them in `lib/bookshelf` because they're decoupled from the web application.
-Later, you may want to add books via an admin portal, an API, or even a command-line utility.
-
-Let's call our interactor `AddBook`,
-and write a new spec `spec/bookshelf/interactors/add_book_spec.rb`:
-
-```ruby
-require 'spec_helper'
-
-describe AddBook do
- let(:interactor) { AddBook.new }
-
- it "succeeds" do
- expect(interactor.call).to be_a_success
- end
-end
-```
-
-(Note: Hanami has no specific RSpec integrations,
-this expectation works because `Hanami::Interactor` defines a `success?` class,
-which [RSpec lets us delegate to with `be_a_success`](https://relishapp.com/rspec/rspec-expectations/docs/built-in-matchers/predicate-matchers)
-
-Running your test suite will cause a NameError because there is no `AddBook` class.
-Let's create that class in a `lib/bookshelf/interactors/add_book.rb` file:
-
-```ruby
-require 'hanami/interactor'
-
-class AddBook
- include Hanami::Interactor
-
- def initialize
- # set up the object
- end
-
- def call(book_attributes)
- # get it done
- end
-end
-```
-
-These are the only two public methods this class should ever have:
-`initialize`, to set-up the data, and
-`call` to actually fulfill the use-case.
-
-These methods, especially `call`, should call private methods that you'll write.
-
-By default, the result is considered a success,
-since we didn't say that it explicitly say it failed.
-
-Let's run this test:
-
-```shell
-% bundle exec rake
-```
-
-All the tests should pass!
-
-Now, let's make our `AddBook` Interactor actually do something!
-
-
-# Creating a Book
-
-Edit `spec/bookshelf/interactors/add_book_spec.rb`:
-
-```ruby
-require 'spec_helper'
-
-describe AddBook do
- let(:interactor) { AddBook.new }
- let(:attributes) { Hash[author: "James Baldwin", title: "The Fire Next Time"] }
-
- describe "good input" do
- let(:result) { interactor.call(attributes) }
-
- it "succeeds" do
- expect(result).to be_a_success
- end
-
- it "creates a Book with correct title and author" do
- expect(result.book.title).to eq("The Fire Next Time")
- expect(result.book.author).to eq("James Baldwin")
- end
- end
-end
-```
-
-If you run the tests with `bundle exec rake`, you'll see this error:
-```ruby
-NoMethodError: undefined method `book' for #
-```
-
-Let's fill out our Interactor,
-then explain what we did:
-
-```ruby
-require 'hanami/interactor'
-
-class AddBook
- include Hanami::Interactor
-
- expose :book
-
- def initialize
- # set up the object
- end
-
- def call(book_attributes)
- @book = Book.new(book_attributes)
- end
-end
-```
-
-There are two important things to note here:
-
-The `expose :book` line exposes the `@book` instance variable as a method on the result that will be returned.
-
-The `call` method assigns a new Book entity to the `@book` variable, which will be exposed to the result.
-
-The tests should pass now.
-
-We've initialized a new Book entity, but it's not persisted to the database.
-
-# Persisting the Book
-We have a new `Book` built from the title and author passed in,
-but it doesn't exist in the database yet.
-
-We need to use our `BookRepository` to persist it.
-
-```ruby
-require 'spec_helper'
-
-describe AddBook do
- let(:interactor) { AddBook.new }
- let(:attributes) { Hash[author: "James Baldwin", title: "The Fire Next Time"] }
-
- describe "good input" do
- let(:result) { interactor.call(attributes) }
-
- it "succeeds" do
- expect(result).to be_a_success
- end
-
- it "creates a Book with correct title and author" do
- expect(result.book.title).to eq("The Fire Next Time")
- expect(result.book.author).to eq("James Baldwin")
- end
-
- it "persists the Book" do
- expect(result.book.id).to_not be_nil
- end
- end
-end
-```
-
-If you run the tests,
-you'll see the new expectation fails with `Expected nil to not be nil.`
-
-This is because the book we built doesn't have an `id`,
-since it only gets one if and when it is persisted.
-
-To make this test pass, we'll need to create a _persisted_ `Book` instead.
-(Another, equally valid, option would be to persist the Book we already have.)
-
-Edit the `call` method in our `lib/bookshelf/interactors/add_book.rb` Interactor:
-
-```ruby
- def call
- @book = BookRepository.new.create(book_attributes)
- end
-```
-
-Instead of calling `Book.new`,
-we create a new `BookRepository` and send `create` to it, with our attributes.
-
-This still returns a `Book`, but it also persists this record to the database.
-
-If you run the tests now you'll see all the tests pass.
-
-# Dependency Injection
-Let's refactor our implementation though,
-to leverage [Dependency Injection](https://martinfowler.com/articles/injection.html)
-
-We recommend you use Dependency Injection, but you don't have to.
-This is an entirely optional feature of Hanami's Interactor.
-
-The spec so far works,
-but it relies on the behavior of the Repository
-(that the `id` method is defined after persistence succeeds).
-That is an implementation detail of how the Repository works.
-For example, if you wanted to create a UUID *before* it's persisted,
-and signify the persistence was successful in some other way than populating an `id` column,
-you'd have to modify this spec.
-
-We can change our spec and our Interactor to make it more robust:
-it'll be less likely to break because of changes outside of its file.
-
-Here's how we can use Dependency Injection in our Interactor:
-
-```ruby
-require 'hanami/interactor'
-
-class AddBook
- include Hanami::Interactor
-
- expose :book
-
- def initialize(repository: BookRepository.new)
- @repository = repository
- end
-
- def call(book_attributes)
- @book = @repository.create(book_attributes)
- end
-end
-```
-
-It's basically the same thing, with a little bit more code,
-to create the `@repository` instance variable.
-
-Right now, our spec tests the behavior of the repository,
-by checking to make sure `id` is populated
-(`expect(result.book.id).to_not be_nil`).
-
-This is an implementation detail.
-
-Instead, we can change our spec to merely make sure the repository receives the `create` message,
-and trust that the repository will persist it (since that is its responsibility).
-
-Let's change remove our `it "persists the Book"` expectation and
-create a `describe "persistence"` block:
-
-```ruby
-require 'spec_helper'
-
-describe AddBook do
- let(:interactor) { AddBook.new }
- let(:attributes) { Hash[author: "James Baldwin", title: "The Fire Next Time"] }
-
- describe "good input" do
- let(:result) { interactor.call(attributes) }
-
- it "succeeds" do
- expect(result).to be_a_success
- end
-
- it "creates a Book with correct title and author" do
- expect(result.book.title).to eq("The Fire Next Time")
- expect(result.book.author).to eq("James Baldwin")
- end
- end
-
- describe "persistence" do
- let(:repository) { instance_double("BookRepository") }
-
- it "persists the Book" do
- expect(repository).to receive(:create)
- AddBook.new(repository: repository).call(attributes)
- end
- end
-end
-```
-
-Now our test doesn't violate the boundaries of the concern.
-
-What we did here is **inject** our Interactor's dependency on the repository.
-Note: in our non-test code, we don't need to change anything.
-The default value for the `repository:` keyword argument provides a new repository object if one is not passed in.
-
-# Email notification
-Let's add the email notification!
-
-You can use a different library,
-but we'll use `Hanami::Mailer`.
-(You could do anything here, like send an SMS, send a chat message, or call a webhook.)
-
-```shell
-% bundle exec hanami generate mailer book_added_notification
- create lib/bookshelf/mailers/book_added_notification.rb
- create spec/bookshelf/mailers/book_added_notification_spec.rb
- create lib/bookshelf/mailers/templates/book_added_notification.txt.erb
- create lib/bookshelf/mailers/templates/book_added_notification.html.erb
-```
-
-We won't get into the details of [how the mailer works](/guides/mailers/overview),
-but it's pretty simple: there's a `Hanami::Mailer` class, an associated spec,
-and two templates (one for plaintext, and one for html).
-
-We'll keep our templates empty,
-so the emails will be blank,
-with a subject line saying 'Book added!'.
-
-Edit the mailer spec `spec/bookshelf/mailers/book_added_notification_spec.rb`:
-
-```ruby
-RSpec.describe Mailers::BookAddedNotification, type: :mailer do
- subject { Mailers::BookAddedNotification }
-
- before { Hanami::Mailer.deliveries.clear }
-
- it 'has correct `from` email address' do
- expect(subject.from).to eq("no-reply@example.com")
- end
-
- it 'has correct `to` email address' do
- expect(subject.to).to eq("admin@example.com")
- end
-
- it 'has correct `subject`' do
- expect(subject.subject).to eq("Book added!")
- end
-
- it 'delivers mail' do
- expect {
- subject.deliver
- }.to change { Hanami::Mailer.deliveries.length }.by(1)
- end
-end
-```
-
-
-And edit the mailer `lib/bookshelf/mailers/book_added_notification.rb`:
-
-```ruby
-class Mailers::BookAddedNotification
- include Hanami::Mailer
-
- from 'no-reply@example.com'
- to 'admin@example.com'
- subject 'Book added!'
-end
-```
-
-Now all our tests should pass!
-
-
-But, this Mailer isn't called from anywhere.
-We need to call this Mailer from our `AddBook` Interactor.
-
-Let's edit our `AddBook` spec, to ensure our mailer is called:
-
-```ruby
- ...
- describe "sending email" do
- let(:mailer) { instance_double("Mailers::BookAddedNotification") }
-
- it "send :deliver to the mailer" do
- expect(mailer).to receive(:deliver)
- AddBook.new(mailer: mailer).call(attributes)
- end
- end
- ...
-```
-
-Running your test suite will show an error: `ArgumentError: unknown keyword: mailer`.
-This makes sense, since our Interactor only a singular keyword argument: `repository`.
-
-Let's integrate our mailer now,
-by adding a new `mailer` keyword argument on the initializer.
-
-We'll also call `deliver` on our new `@mailer` instance variable.
-
-```ruby
-require 'hanami/interactor'
-
-class AddBook
- include Hanami::Interactor
-
- expose :book
-
- def initialize(repository: BookRepository.new, mailer: Mailers::BookAddedNotification.new)
- @repository = repository
- @mailer = mailer
- end
-
- def call(title:, author:)
- @book = @repository.create({title: title, author: author})
- @mailer.deliver
- end
-end
-```
-
-Now our Interactor will deliver an email, notifying that a book has been added.
-
-# Interactor parts
-## Interface
-The interface is rather simple, as shown above.
-There's also one more method you can (optionally) implement.
-It's a private method named `valid?`.
-
-By default `valid?` returns true.
-If you define `valid?` and it ever returns `false`,
-then `call` will never be executed.
-
-Instead, the result will be returned immediately.
-This also causes the result to be a failure (instead of a success.)
-
-You can read about it in the
-[API documentation](http://www.rubydoc.info/gems/hanami-utils/Hanami/Interactor/Interface)
-
-## Result
-The result of `Hanami::Interactor#call` is a `Hanami::Interactor::Result` object.
-
-It will have accessor methods defined for whatever instance variables you
-`expose`.
-
-It also has the ability to keep track of errors.
-
-In your interactor, you can call `error` with a message,
-to add an error.
-This automatically makes the resulting object a failure.
-
-(There's also an `error!` method,
-which does the same *and* also interrupts the flow,
-stopping the Interactor from executing more code).
-
-You can access the errors on the resulting object, by calling `.errors`.
-
-You can read more about the Result object in the
-[API documentation](http://www.rubydoc.info/gems/hanami-utils/Hanami/Interactor/Result).
diff --git a/source/guides/1.1/architecture/overview.md b/source/guides/1.1/architecture/overview.md
deleted file mode 100644
index 444003cde..000000000
--- a/source/guides/1.1/architecture/overview.md
+++ /dev/null
@@ -1,137 +0,0 @@
----
-title: "Guides - Architectures: Container"
-version: 1.1
----
-
-# Architectures
-
-Hanami is based on two principles: [Clean Architecture](https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html) and [Monolith First](http://martinfowler.com/bliki/MonolithFirst.html).
-
-## Clean Architecture
-
-The main purpose of this architecture is to enforce a **separation of concerns** between the **core** of our product and the **delivery mechanisms**.
-The first is expressed by the set of **use cases** that our product implements, while the latter are interfaces to make these features available to the outside world.
-
-When we generate a new project we can find two important directories: `lib/` and `apps/`.
-They are home to the main parts described above.
-
-### Application Core
-
-We implement a set of functionalities, without worrying about how they can be exposed to the outside world.
-This is the **cornerstone** of our product, and we want to be careful on how we manage dependencies for it.
-
-`Hanami::Model` is the default choice for persisting our Ruby objects.
-This is a _soft-dependency_, it can be removed from our `Gemfile` and replaced with something else.
-
-Let's have a look at how the `lib/` directory appears for a new generated project called `bookshelf` that uses `Hanami::Model`.
-
-```shell
-% tree lib
-lib
-βββ bookshelf
-βΒ Β βββ entities
-βΒ Β βββ mailers
-βΒ Β βΒ Β βββ templates
-βΒ Β βββ repositories
-βββ bookshelf.rb
-
-5 directories, 1 file
-```
-
-The idea is to develop our application like a Ruby gem.
-
-The `lib/bookshelf.rb` file is the entry point for our application, when we require this file, we require and initialize all the code under `lib/`.
-
-There are two important directories:
-
- * `lib/bookshelf/entities`
- * `lib/bookshelf/repositories`
-
-They contain [entities](/guides/1.1/models/entities) that are Ruby objects at the core of our model domain, and they aren't aware of any persistence mechanism.
-For this purpose we have a separate concept, [repositories](/guides/1.1/models/repositories), which are a mediator between our entities and the underlying database.
-
-For each entity named `Book` we can have a `BookRepository`.
-
-We can add as many directories that we want, such as `lib/bookshelf/interactors` to implement our use cases.
-
-### Delivery Mechanisms
-
-Hanami generates a default application named `Web`, which lives under `apps/web`.
-This application **depends** on the core of our product, as it uses entities, repositories and all the other objects defined there.
-
-It's used as web delivery mechanism, for our features.
-
-```shell
-% tree apps/web
-apps/web
-βββ application.rb
-βββ assets
-βΒ Β βββ favicon.ico
-βΒ Β βββ images
-βΒ Β βββ javascripts
-βΒ Β βββ stylesheets
-βββ config
-βΒ Β βββ routes.rb
-βββ controllers
-βββ templates
-βΒ Β βββ application.html.erb
-βββ views
- βββ application_layout.rb
-
-8 directories, 5 files
-```
-
-Let's have a quick look at this code.
-
-The file `apps/web/application.rb` contains a Hanami application named `Web::Application`, here we can configure all the settings for this **component** of our project.
-Directories such as `apps/web/controllers`, `views` and `templates` will contain our [actions](/guides/1.1/actions/overview), [views](/guides/1.1/views/overview) and [templates](/guides/1.1/views/templates).
-
-Web assets such as javascripts and stylesheets will be automatically served by the application.
-
-## Monolith First
-
-Our default application `Web` can be used as a UI interface for our customers.
-At a certain point in our story, we want to manage our users with an admin panel.
-
-We know that the set of features that we're going to introduce doesn't belong to our main UI (`Web`).
-On the other hand, it's **too early** for us to implement a microservices architecture, only for the purpose of helping our users reset their password.
-
-Hanami has a solution for our problem: we can generate a new app that lives in the same Ruby process, but it's a separated component.
-
-```shell
-% bundle exec hanami generate app admin
-```
-
-This command MUST be run from the root of our project. It will generate a new application (`Admin::Application`) under `apps/admin`.
-
-In the late stages of our product life-cycle, we could decide to extract this into a standalone component.
-We would just need to move everything under `apps/admin` into another repository and deploy it separately.
-
-## Anatomy Of A Project
-
-We have already examined `lib/` and `apps/`, but there are other parts of a newly generated project that deserve to be explained.
-
-```shell
-% tree -L 1
-.
-βββ Gemfile
-βββ Gemfile.lock
-βββ Rakefile
-βββ apps
-βββ config
-βββ config.ru
-βββ db
-βββ lib
-βββ spec
-```
-
-Let's quickly introduce them:
-
- * `Gemfile` and `Gemfile.lock` are [Bundler](http://bundler.io) artifacts
- * `Rakefile` describes Rake task for our project.
- * `config/` contains an important file `config/environment.rb`, which is the **entry point** for our project.
- By requiring it, we'll preload our dependencies (Ruby gems), Hanami frameworks and our code.
- * `config.ru` is a file that describes how a Rack server must run our applications.
- * `db/` contains database files (for File System adapter or SQLite).
- When our project uses a SQL database it also contains `db/migrations` and `db/schema.sql`.
- * `spec/` contains unit and acceptance tests.
diff --git a/source/guides/1.1/assets/compressors.md b/source/guides/1.1/assets/compressors.md
deleted file mode 100644
index a4e811c00..000000000
--- a/source/guides/1.1/assets/compressors.md
+++ /dev/null
@@ -1,87 +0,0 @@
----
-title: Guides - Assets Compressors
-version: 1.1
----
-
-# Assets
-
-## Compressors
-
-Assets compression (aka minification) is a process to shrink the file size of a file in order to reduce the time that a browser needs to download it.
-Usually, it's applied to javascripts and stylesheets.
-
-In order to set one of the following engines, we need to open `apps/web/application.rb` and write:
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- assets do
- javascript_compressor :builtin
- stylesheet_compressor :builtin
-
- # ...
- end
- end
- end
-end
-```
-
-If we want to skip compression, just comment one or both the lines above.
-
-### JavaScript
-
-We support the following engines:
-
- * `:builtin` - It isn't efficient like the other algorithms, but it's a good starting point because it's written in **pure Ruby** and **it doesn't require external dependencies**.
- * `:yui` - It's based on [Yahoo! YUI Compressor](http://yui.github.io/yuicompressor). It requires [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and Java 1.4+
- * `:uglifier` - It's based on [UglifyJS2](http://lisperator.net/uglifyjs). It requires [uglifier](https://rubygems.org/gems/uglifier) gem and Node.js
- * `:closure` - It's based on [Google Closure Compiler](https://developers.google.com/closure/compiler). It requires [`closure-compiler`](https://rubygems.org/gems/closure-compiler) gem and Java
-
-
- In order to use :yui
, :uglifier
and :closure
compressors, you need to add the corresponding gem to Gemfile
.
-
-
-### Stylesheet
-
-We support the following engines:
-
- * `:builtin` - It isn't efficient like the other algorithms, but it's a good starting point because it's written in **pure Ruby** and **it doesn't require external dependencies**.
- * `:yui` - It's based on [Yahoo! YUI Compressor](http://yui.github.io/yuicompressor). It requires [`yui-compressor`](https://rubygems.org/gems/yui-compressor) gem and Java 1.4+
- * `:sass` - It's based on [Sass](http://sass-lang.com). It requires [sass](https://rubygems.org/gems/sass) gem
-
-
- In order to use :yui
, and :sass
compressors, you need to add the corresponding gem to Gemfile
.
-
-
-### Custom Compressors
-
-We can use our own compressor for **both JS and CSS**.
-It **MUST** respond to `#compress(filename)` and return a `String` with the minification output.
-
-```ruby
-class MyCustomJavascriptCompressor
- def compress(filename)
- # ...
- end
-end
-```
-
-Then we can use it with our configuration:
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- assets do
- javascript_compressor MyCustomJavascriptCompressor.new
- stylesheet_compressor :builtin
-
- # ...
- end
- end
- end
-end
-```
diff --git a/source/guides/1.1/assets/content-delivery-network.md b/source/guides/1.1/assets/content-delivery-network.md
deleted file mode 100644
index d97eb9c65..000000000
--- a/source/guides/1.1/assets/content-delivery-network.md
+++ /dev/null
@@ -1,138 +0,0 @@
----
-title: Guides - Assets Content Delivery Network (CDN)
-version: 1.1
----
-
-# Assets
-
-## Content Delivery Network (CDN)
-
-A Hanami application can serve assets from a [Content Delivery Network](https://en.wikipedia.org/wiki/Content_delivery_network) (CDN).
-This feature is useful in _production_ environment, where we want to speed up static assets serving.
-
-In order to take advantage of this feature, we need to specify CDN settings.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- # ...
- configure :production do
- scheme 'https'
- host 'bookshelf.org'
- port 443
-
- assets do
- # ...
- fingerprint true
-
- # CDN settings
- scheme 'https'
- host '123.cloudfront.net'
- port 443
- end
- end
- end
-end
-```
-
-Once _CDN mode_ is on, all the [asset helpers](/guides/1.1/helpers/assets) will return **absolute URLs**.
-
-```erb
-<%= stylesheet 'application' %>
-```
-
-```html
-
-```
-
-## Subresource Integrity
-
-A CDN can dramatically improve page speed, but it can potentially open a security breach.
-If the CDN that we're using is compromised and serves evil javascript or stylesheet files, we're exposing our users to security attacks like Cross Site Scripting (XSS).
-
-To solve this problem, browsers vendors introduced a defense called [Subresource Integrity](https://developer.mozilla.org/en-US/docs/Web/Security/Subresource_Integrity).
-
-When enabled, the browser verifies that the checksum of the downloaded file, matches with the declared one.
-
-### From A CDN
-
-If we're using jQuery from their CDN, we should find the checksum of the `.js` file on their website and write:
-
-```erb
-<%= javascript 'https://code.jquery.com/jquery-3.1.0.min.js', integrity: 'sha256-cCueBR6CsyA4/9szpPfrX3s49M9vUU5BgtiJj06wt/s=' %>
-```
-
-The output will be:
-
-```html
-
-```
-
-### Content Security Policy (CSP)
-
-By default, Hanami sets a Content-Security-Policy header which does not allow for the execution of external JavaScript code.
-
-Let's say we want to use [Bootstrap](https://getbootstrap.com/) in our `web` application, we have to explicitly allow for the use of the relevant CDNs in `app/web/application.rb` by appending them in the `script-src` field:
-
-```ruby
- security.content_security_policy %{
- β¦
- script-src 'self' \
- https://code.jquery.com \
- https://cdnjs.cloudflare.com \
- https://maxcdn.bootstrapcdn.com;
- β¦
- }
-```
-
-Read more about the CSP header in the [security guide](/guides/1.1/projects/security/#content-security-policy).
-
-### Local Assets
-
-The security problem described above doesn't concern only CDNs, but local files too.
-Imagine we have a compromised file system and someone was able to replace our javascripts with evil files: we would be vulnerable to the same kind of attack.
-
-As a defense against this security problem, Hanami **enables Subresource Integrity by default in production.**
-When we [precompile assets](/guides/1.1/command-line/assets) at deploy time, Hanami calculates the checksum of all our assets and it adds a special HTML attribute `integrity` to our asset tags like `
-```
-
-### Settings
-
-To turn off this feature, or to configure it, please have a look at the `production` block in `apps/web/application.rb`
-
-```ruby
-module Web
- class Application < Hanami::Application
- configure :production do
- assets do
- # ...
- subresource_integrity :sha256
- end
- end
- end
-end
-```
-
-By removing or commenting that line, the feature is turned off.
-
-We can choose one or more checksum algorithms:
-
-```ruby
-subresource_integrity :sha256, :sha512
-```
-
-With this setting, Hanami will render `integrity` HTML attribute with two values: one for `SHA256` and one for `SHA512`.
-
-```html
-
-```
-
-**Please note** that checksum calculations are CPU intensive, so adding an additional `subresource_integrity` scheme will extend the time it takes to _precompile assests_, and therefore deploy. We suggest leaving the default setting (`:sha256`).
diff --git a/source/guides/1.1/assets/overview.md b/source/guides/1.1/assets/overview.md
deleted file mode 100644
index d2019bacb..000000000
--- a/source/guides/1.1/assets/overview.md
+++ /dev/null
@@ -1,255 +0,0 @@
----
-title: Guides - Assets Overview
-version: 1.1
----
-
-# Assets
-
-Hanami supports powerful features for web assets.
-
-## Configuration
-
-Each application can have its own separated assets settings in application configuration.
-
-### Compile Mode
-
-Toggle this value, to determine if the application must preprocess or copy assets from sources to public directory.
-It's turned on by default in _development_ and _test_ environments, but turned off for _production_.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- assets do
- # compile true, enabled by default
- end
- end
-
- configure :production do
- assets do
- compile false
- end
- end
- end
-end
-```
-
-### Fingerprint Mode
-
-In order to force browsers to cache the right copy of an asset, during the deploy, Hanami creates a copy of each file by [appending its checksum](/guides/1.1/command-line/assets) to the file name.
-
-We can control this feature via application configuration.
-It's turned on by default only in _production_ environment.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- assets do
- # fingerprint false, disabled by default
- end
- end
-
- configure :production do
- assets do
- fingerprint true
- end
- end
- end
-end
-```
-
-If enabled, [assets helpers](/guides/1.1/helpers/assets) will generate checksum relative URLs.
-
-```erb
-<%= javascript 'application' %>
-```
-
-```html
-
-```
-
-## Serve Static Assets
-
-It can dynamically serve them during development.
-It mounts `Hanami::Static` middleware in project Rack stack. This component is conditionally activated, if the environment variable `SERVE_STATIC_ASSETS` equals to `true`.
-
-By default, new projects are generated with this feature enabled in _development_ and _test_ mode, via their corresponding `.env.*` files.
-
-```
-# .env.development
-# ...
-SERVE_STATIC_ASSETS="true"
-```
-
-Hanami assumes that projects in _production_ mode are deployed using a web server like Nginx that is responsible to serve them without even hitting the Ruby code.
-
-
- Static assets serving is enabled by default in development and test environments, but turned off for production .
-
-
-There are cases where this assumption isn't true. For instance, Heroku requires Ruby web apps to serve static assets.
-To enable this feature in production, just make sure that this special environment variable is set to `true` (in `.env` or `.env.production`).
-
-### What Does It Mean To Serve Static Assets With Hanami?
-
-As mentioned above, when this feature is enabled, a special middleware is added in front of the project Rack stack: `Hanami::Static`.
-
-Incoming requests can generate the following use cases
-
-#### Fresh Asset
-
-```
-GET /assets/application.js
-```
-
-It copies the `apps/web/assets/javascripts/application.js` to `public/assets/application.js` and then serves it.
-
-
- Assets are copied only if the destination path does NOT exist (eg. public/assets/application.js
).
- If it DOES exist, the asset is only served, without copying it.
-
-
-
- When an application has turned OFF asset compilation (Compile mode), Hanami won't copy the file.
-
-
-#### Stale Asset
-
-This could happen in _development_ mode. When we require an asset the first time it gets copied to the `public/` directory. Then when we edit the source file, the destination file becomes stale.
-
-```
-GET /assets/application.js
-# edit the original file: apps/web/assets/javascripts/application.js
-# then require it again
-GET /assets/application.js
-```
-
-It copies the source into the destination file **again** (`public/assets/application.js`) and then serves it.
-
-#### Precompiled Asset
-
-Let's say we use Sass to write our stylesheets.
-
-```
-GET /assets/application.css
-```
-
-It preprocess the `apps/web/assets/stylesheet/application.css.sass` to `public/assets/application.css` and then serves it.
-
-#### Dynamic Resource
-
-```
-GET /books/23
-```
-
-This isn't a static file available under `public/`, so the control passes to the backend that hits the appropriate action.
-
-#### Missing Resource
-
-```
-GET /unknown
-```
-
-This isn't a static file or a dynamic resource, the project returns a `404 (Not Found)`.
-
-## Sources
-
-Each application has a separated set of directories where its assets can be found.
-Assets are recursively searched under these paths.
-
-New projects have a default directory where application assets can be put:
-
-```
-% tree apps/web/assets
-apps/web/assets
-βββ favicon.ico
-βββ images
-βββ javascripts
-βββ stylesheets
-
-3 directories, 1 file
-```
-
-We can add as many directories we want under it (eg. `apps/web/assets/fonts`).
-
-
- For a given application named Web
, the default asset directory is apps/web/assets
-
-
-### Adding Sources
-
-If we want add other sources for a given application, we can specify them in the configuration.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- assets do
- # apps/web/assets is added by default
- sources << [
- 'vendor/assets'
- ]
- end
- end
- end
-end
-```
-
-This will add `apps/web/vendor/assets` and all its subdirectories.
-
-
- Hanami looks recursively through the asset sources. In order to NOT accidentally disclose sensitive files like secrets or source code, please make sure that these sources directories ONLY contain web assets.
-
-
-## Third Party Gems
-
-Hanami allows developers to use [Rubygems](https://rubygems.org) as a way to distribute web assets and make them available to Hanami applications.
-
-Third party gems can be maintained by developers who want to bring frontend framework support to Hanami.
-Let's say we want to build an `hanami-emberjs` gem.
-
-```shell
-% tree .
-# ...
-βββ lib
-βΒ Β βββ hanami
-βΒ Β βββ emberjs
-βΒ Β βΒ Β βββ dist
-βΒ Β βΒ Β βΒ Β βββ ember.js
-βΒ Β βΒ Β βΒ Β βββ ember.min.js
-βΒ Β βΒ Β βββ version.rb
-βΒ Β βββ emberjs.rb
-βββ hanami-emberjs.gemspec
-# ...
-```
-
-We put **only** the assets that we want to serve in an **arbitrary** directory.
-Then we add it to `Hanami::Assets.sources`.
-
-```ruby
-# lib/hanami/emberjs.rb
-require 'hanami/assets'
-
-module Hanami
- module Emberjs
- require 'hanami/emberjs/version'
- end
-end
-
-Hanami::Assets.sources << __dir__ + '/emberjs/source'
-```
-
-When an application requires `'hanami/emberjs'`, that directory will be added to the sources where Hanami can search for assets.
-
-```erb
-<%= javascript 'ember' %>
-```
-
-We can use the `javascript` [helper](/guides/1.1/helpers/assets) to include `ember.js` in our application.
diff --git a/source/guides/1.1/assets/preprocessors.md b/source/guides/1.1/assets/preprocessors.md
deleted file mode 100644
index 52d5b2863..000000000
--- a/source/guides/1.1/assets/preprocessors.md
+++ /dev/null
@@ -1,98 +0,0 @@
----
-title: Guides - Assets Preprocessors
-version: 1.1
----
-
-# Assets
-
-## Preprocessors
-
-Hanami is able to run assets preprocessors and **lazily compile** them under `public/assets`.
-
-Imagine to have `application.css.scss` in `apps/web/assets/stylesheets` and `reset.css` under
-`apps/web/vendor/stylesheets`.
-
-**The extensions structure is important.**
-The first one is mandatory and it's used to understand which asset type we are
-handling: `.css` for stylesheets.
-The second one is optional and it's for a preprocessor: `.scss` for Sass.
-
-
- For a given asset application.css.scss
, the last extension (.scss
) is used to determine the right preprocessor.
-
-
-
- Preprocessors are optional, an application can work with plain javascripts or stylesheets. In this case we have to name our assets with only one extension (eg application.css
).
-
-
-```ruby
-# apps/web/application.rb
-require 'sass'
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- assets do
- sources << [
- # apps/web/assets is added by default
- 'vendor/assets' # app/web/vendor/assets
- ]
- end
- end
- end
-end
-```
-
-From a template we do:
-
-```erb
-<%= stylesheet 'reset', 'application' %>
-```
-
-When we'll load the page the compiler will preprocess or copy the assets into `public/assets`.
-
-```shell
-% tree public
-public/
-βββ assets
- βββ application.css
- βββ reset.css
-```
-
-Preprocessors will compile/copy assets only if the [_Compile mode_](/guides/1.1/assets/overview) is on.
-
-
- Preprocessors are enabled by default in development and test environments.
-
-
-For performance reasons, this feature is turned off in _production_ env, where we should [precompile](/guides/1.1/command-line/assets) our assets.
-
-### Preprocessors Engines
-
-Hanami uses [Tilt](https://github.com/rtomayko/tilt) to provide support for the most common preprocessors, such as [Sass](http://sass-lang.com/) (including `sassc-ruby`), [Less](http://lesscss.org/), ES6, [JSX](https://jsx.github.io/), [CoffeScript](http://coffeescript.org), [Opal](http://opalrb.org), [Handlebars](http://handlebarsjs.com), [JBuilder](https://github.com/rails/jbuilder).
-
-In order to use one or more of them, be sure to include the corresponding gem into your `Gemfile` and require the library.
-
-```ruby
-# Gemfile
-# ...
-gem 'sass'
-```
-
-
- Some preprocessors may require Node.js. Please check the documentation.
-
-
-#### EcmaScript 6
-
-We strongly suggest to use [EcmaScript 6](http://es6-features.org/) for your next project, because that is the next version of JavaScript.
-It isn't fully [supported](https://kangax.github.io/compat-table/es6/) yet by browser vendors, but this is changing quickly.
-
-As of today, you need to transpile ES6 code into something understandable by current browsers, which is ES5.
-For this purpose we support [Babel](https://babeljs.io).
-
-
- Babel requires Node.js.
-
diff --git a/source/guides/1.1/assets/use-your-own-assets-management-tool.md b/source/guides/1.1/assets/use-your-own-assets-management-tool.md
deleted file mode 100644
index 2c3f2f3e4..000000000
--- a/source/guides/1.1/assets/use-your-own-assets-management-tool.md
+++ /dev/null
@@ -1,17 +0,0 @@
----
-title: Guides - Use Your Own Assets Management
-version: 1.1
----
-
-# Use Your Own Assets Management
-
-Hanami tries to cover basic use cases for assets management: [(pre)compilation](/guides/1.1/assets/overview/#compile-mode), [compression](/guides/1.1/assets/compressors), [fingerprinting](/guides/1.1/assets/overview/#fingerprint-mode), [Content Delivery Network (CDN)](/guides/1.1/assets/content-delivery-network) with [Subresource Integrity](/guides/1.1/assets/content-delivery-network/#subresource-integrity).
-
-If it still doesn't fit your needs, you can use your own assets management tool such as Webpack.
-
-## Deployment
-
-To do so, please organize the assets according to your assets management tool and **don't** run `bundle exec hanami assets precompile` when deploying your project, but follow the instructions of your assets management software.
-
-Please remember that for compatibility with the [Ruby server hosting ecosystem](/guides/1.1/projects/rake/#ruby-server-hosting-ecosystem-compatibility), we make available a special Rake task `assets:precompile`, which is run automatically by SaaS vendors.
-If this is your situation, you may want override this task in the `Rakefile` of your project, with something more useful for you.
diff --git a/source/guides/1.1/associations/belongs-to.md b/source/guides/1.1/associations/belongs-to.md
deleted file mode 100644
index 9e0af1e44..000000000
--- a/source/guides/1.1/associations/belongs-to.md
+++ /dev/null
@@ -1,134 +0,0 @@
----
-title: "Guides - Associations: Belongs To"
-version: 1.1
----
-
-# Belongs To
-
-Also known as _many-to-one_, is an association between a one of the entities (`Book`) associated to one parent entity (`Author`).
-
-## Setup
-
-```shell
-% bundle exec hanami generate model author
- create lib/bookshelf/entities/author.rb
- create lib/bookshelf/repositories/author_repository.rb
- create db/migrations/20171024081558_create_authors.rb
- create spec/bookshelf/entities/author_spec.rb
- create spec/bookshelf/repositories/author_repository_spec.rb
-
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create db/migrations/20171024081617_create_books.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-Edit the migrations:
-
-```ruby
-# db/migrations/20171024081558_create_authors.rb
-Hanami::Model.migration do
- change do
- create_table :authors do
- primary_key :id
-
- column :name, String, null: false
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```ruby
-# db/migrations/20171024081617_create_books.rb
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
-
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-
- column :title, String, null: false
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-Now we can prepare the database:
-
-```shell
-% bundle exec hanami db prepare
-```
-
-## Usage
-
-### Basic usage
-
-Let's edit `BookRepository` with the following code:
-
-```ruby
-# lib/bookshelf/repositories/book_repository.rb
-class BookRepository < Hanami::Repository
- associations do
- belongs_to :author
- end
-
- def find_with_author(id)
- aggregate(:author).where(id: id).map_to(Book).one
- end
-end
-```
-
-We have defined [explicit methods](/guides/1.1/associations/overview#explicit-interface) only for the operations that we need for our model domain.
-In this way, we avoid to bloat `BookRepository` with dozen of unneeded methods.
-
-Let's create a book:
-
-```ruby
-repository = BookRepository.new
-
-book = repository.create(author_id: 1, title: "Hanami")
- # => #1, :author_id=>1, :created_at=>2017-10-24 08:25:41 UTC, :updated_at=>2017-10-24 08:25:41 UTC}>
-```
-
-What happens if we load the author with `BookRepository#find`?
-
-```ruby
-book = repository.find(book.id)
- # => #1, :author_id=>1, :created_at=>2017-10-24 08:25:41 UTC, :updated_at=>2017-10-24 08:25:41 UTC}>
-book.author
- # => nil
-```
-
-Because we haven't [explicitly loaded](/guides/1.1/associations/overview#explicit-loading) the associated records, `book.author` is `nil`.
-We can use the method that we have defined on before (`#find_with_author`):
-
-```ruby
-book = repository.find_with_author(book.id)
- # => #1, :author_id=>1, :created_at=>2017-10-24 08:25:41 UTC, :updated_at=>2017-10-24 08:25:41 UTC, :author=>#1, :name=>"Luca", :created_at=>2017-10-24 08:25:15 UTC, :updated_at=>2017-10-24 08:25:15 UTC}>}>
-
-book.author
- # => => #1, :name=>"Luca", :created_at=>2017-10-24 08:25:15 UTC, :updated_at=>2017-10-24 08:25:15 UTC}>
-```
-
-This time `book.author` has the collection of associated author.
-
-### Remove
-
-What if we need to unassociate a book from its author?
-
-Because we declared a _foreign key_ with the [migration](#setup), we cannot set `author_id` to `NULL` or to reference to an unexisting author.
-This is a mechanism against [_orphaned records_](http://database.guide/what-is-an-orphaned-record/): a book is forced to reference a valid author.
-
-The only way to remove a book from an author is to delete the book record.
-
-```ruby
-repository.delete(book.id)
-repository.find(book.id)
- # => nil
-```
diff --git a/source/guides/1.1/associations/has-many-through.md b/source/guides/1.1/associations/has-many-through.md
deleted file mode 100644
index 87b96a95e..000000000
--- a/source/guides/1.1/associations/has-many-through.md
+++ /dev/null
@@ -1,244 +0,0 @@
----
-title: "Guides - Associations: Has Many Through"
-version: 1.1
----
-
-# Has Many Through
-
-Also known as _many-to-many_, is an association between an entity (`Story`) and a collection of many entities (`User`), passing via an intermediate entity (`Comment`).
-
-## Setup
-
-```shell
-% bundle exec hanami generate model user
- create lib/bookshelf/entities/user.rb
- create lib/bookshelf/repositories/user_repository.rb
- create db/migrations/20171024083639_create_users.rb
- create spec/bookshelf/entities/user_spec.rb
- create spec/bookshelf/repositories/user_repository_spec.rb
-
-% bundle exec hanami generate model story
- create lib/bookshelf/entities/story.rb
- create lib/bookshelf/repositories/story_repository.rb
- create db/migrations/20171024085712_create_stories.rb
- create spec/bookshelf/entities/story_spec.rb
- create spec/bookshelf/repositories/story_repository_spec.rb
-
-% bundle exec hanami generate model comment
- create lib/bookshelf/entities/comment.rb
- create lib/bookshelf/repositories/comment_repository.rb
- create db/migrations/20171024085858_create_comments.rb
- create spec/bookshelf/entities/comment_spec.rb
- create spec/bookshelf/repositories/comment_repository_spec.rb
-```
-
-Edit the migrations:
-
-```ruby
-# db/migrations/20171024083639_create_users.rb
-Hanami::Model.migration do
- change do
- create_table :users do
- primary_key :id
-
- column :name, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```ruby
-# db/migrations/20171024085712_create_stories.rb
-Hanami::Model.migration do
- change do
- create_table :stories do
- primary_key :id
-
- foreign_key :user_id, :users, null: false, on_delete: :cascade
-
- column :text, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```ruby
-# db/migrations/20171024085858_create_comments.rb
-Hanami::Model.migration do
- change do
- create_table :comments do
- primary_key :id
-
- foreign_key :user_id, :users, null: false, on_delete: :cascade
- foreign_key :story_id, :stories, null: false, on_delete: :cascade
-
- column :text, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-Now we can prepare the database:
-
-```shell
-% bundle exec hanami db prepare
-```
-
-## Usage
-
-### Basic usage
-
-Let's edit the repositories:
-
-```ruby
-# lib/bookshelf/repositories/user_repository.rb
-class UserRepository < Hanami::Repository
- associations do
- has_many :stories
- has_many :comments
- end
-end
-```
-
-```ruby
-# lib/bookshelf/repositories/story_repository.rb
-class StoryRepository < Hanami::Repository
- associations do
- belongs_to :user
- has_many :comments
- has_many :users, through: :comments
- end
-
- def find_with_comments(id)
- aggregate(:user, comments: :user).where(id: id).map_to(Story).one
- end
-
- def find_with_commenters(id)
- aggregate(:users).where(id: id).map_to(Story).one
- end
-end
-```
-
-```ruby
-# lib/bookshelf/repositories/comment_repository.rb
-class CommentRepository < Hanami::Repository
- associations do
- belongs_to :story
- belongs_to :user
- end
-end
-```
-
-We have defined [explicit methods](/guides/1.1/associations/overview#explicit-interface) only for the operations that we need for our model domain.
-In this way, we avoid to bloat `StoryRepository` with dozen of unneeded methods.
-
-Let's create a couple of users, a story, then a comment:
-
-```ruby
-users = UserRepository.new
-author = users.create(name: "Luca")
- # => #1, :name=>"Luca", :created_at=>2017-10-24 09:06:57 UTC, :updated_at=>2017-10-24 09:06:57 UTC}>
-
-commenter = users.create(name: "Maria G")
- # => #2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>
-```
-
-```ruby
-stories = StoryRepository.new
-
-story = stories.create(user_id: author.id, text: "Hello, folks")
- # => #1, :user_id=>1, :text=>"Hello folks", :created_at=>2017-10-24 09:09:59 UTC, :updated_at=>2017-10-24 09:09:59 UTC}>
-```
-
-```ruby
-comments = CommentRepository.new
-
-comment = comments.create(user_id: commenter.id, story_id: story.id, text: "Hi and welcome!")
- # => #1, :user_id=>2, :story_id=>1, :text=>"Hi and welcome!", :created_at=>2017-10-24 09:12:30 UTC, :updated_at=>2017-10-24 09:12:30 UTC}>
-```
-
-What happens if we load the user with `StoryRepository#find`?
-
-```ruby
-story = stories.find(story.id)
- # => #1, :user_id=>1, :text=>"Hello folks", :created_at=>2017-10-24 09:09:59 UTC, :updated_at=>2017-10-24 09:09:59 UTC}>
-
-story.comments
- # => nil
-```
-
-Because we haven't [explicitly loaded](/guides/1.1/associations/overview#explicit-loading) the associated records `story.comments` is `nil`.
-We can use the method that we have defined on before (`#find_with_comments`):
-
-```ruby
-story = stories.new.find_with_comments(story.id)
- # => #2, :user_id=>1, :text=>"Hello folks", :created_at=>2017-10-24 09:09:59 UTC, :updated_at=>2017-10-24 09:09:59 UTC, :user=>#1, :name=>"Luca", :created_at=>2017-10-24 09:06:57 UTC, :updated_at=>2017-10-24 09:06:57 UTC}>, :comments=>[#1, :user_id=>2, :story_id=>2, :text=>"Hi and welcome!", :created_at=>2017-10-24 09:12:30 UTC, :updated_at=>2017-10-24 09:12:30 UTC, :user=>#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>}>]}>
-
-story.comments
- # => [#1, :user_id=>2, :story_id=>2, :text=>"Hi and welcome!", :created_at=>2017-10-24 09:12:30 UTC, :updated_at=>2017-10-24 09:12:30 UTC, :user=>#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>}>]
-
-story.comments.map(&:user)
- # => [#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>]
-```
-
-This time `story.comments` has the associated records.
-
-Similarly, we can find directly the associated commenters:
-
-```ruby
-story = stories.find_with_commenters(story.id)
- # => #2, :user_id=>1, :text=>"Hello folks", :created_at=>2017-10-24 09:09:59 UTC, :updated_at=>2017-10-24 09:09:59 UTC, :users=>[#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>]}>
-
-story.users
- # => [#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>]
-```
-
-### Aliasing
-
-In the examples above `story.users` was the way to go, because of the Hanami conventions, but that isn't a great name for an association.
-We can alias `users` with something more meaningful like `commenters`:
-
-```ruby
-# lib/bookshelf/repositories/story_repository.rb
-class StoryRepository < Hanami::Repository
- associations do
- belongs_to :user
- has_many :comments
- has_many :users, through: :comments, as: :commenters
- end
-
- def find_with_comments(id)
- aggregate(:user, comments: :commenter).where(id: id).map_to(Story).one
- end
-end
-```
-
-```ruby
-# lib/bookshelf/repositories/comment_repository.rb
-class CommentRepository < Hanami::Repository
- associations do
- belongs_to :story
- belongs_to :user, as: :commenter
- end
-end
-```
-
-```ruby
-story = stories.find_with_comments(2)
- # => #2, :user_id=>1, :text=>"Hello folks", :created_at=>2017-10-24 09:09:59 UTC, :updated_at=>2017-10-24 09:09:59 UTC, :user=>#1, :name=>"Luca", :created_at=>2017-10-24 09:06:57 UTC, :updated_at=>2017-10-24 09:06:57 UTC}>, :comments=>[#1, :user_id=>2, :story_id=>2, :text=>"Hi and welcome!", :created_at=>2017-10-24 09:12:30 UTC, :updated_at=>2017-10-24 09:12:30 UTC, :commenter=>#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>}>]}>
-
-story.comments
- # => [#1, :user_id=>2, :story_id=>2, :text=>"Hi and welcome!", :created_at=>2017-10-24 09:12:30 UTC, :updated_at=>2017-10-24 09:12:30 UTC, :commenter=>#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>}>]
-
-story.comments.map(&:commenter)
- # => [#2, :name=>"Maria G", :created_at=>2017-10-24 09:07:16 UTC, :updated_at=>2017-10-24 09:07:16 UTC}>]
-```
diff --git a/source/guides/1.1/associations/has-many.md b/source/guides/1.1/associations/has-many.md
deleted file mode 100644
index a7f627a41..000000000
--- a/source/guides/1.1/associations/has-many.md
+++ /dev/null
@@ -1,208 +0,0 @@
----
-title: "Guides - Associations: Has Many"
-version: 1.1
----
-
-# Has Many
-
-Also known as _one-to-many_, is an association between a single entity (`Author`) and a collection of many other linked entities (`Book`).
-
-## Setup
-
-```shell
-% bundle exec hanami generate model author
- create lib/bookshelf/entities/author.rb
- create lib/bookshelf/repositories/author_repository.rb
- create db/migrations/20171024081558_create_authors.rb
- create spec/bookshelf/entities/author_spec.rb
- create spec/bookshelf/repositories/author_repository_spec.rb
-
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create db/migrations/20171024081617_create_books.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-Edit the migrations:
-
-```ruby
-# db/migrations/20171024081558_create_authors.rb
-Hanami::Model.migration do
- change do
- create_table :authors do
- primary_key :id
-
- column :name, String, null: false
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```ruby
-# db/migrations/20171024081617_create_books.rb
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
-
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-
- column :title, String, null: false
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-Now we can prepare the database:
-
-```shell
-% bundle exec hanami db prepare
-```
-
-## Usage
-
-### Basic usage
-
-Let's edit `AuthorRepository` with the following code:
-
-```ruby
-# lib/bookshelf/repositories/author_repository.rb
-class AuthorRepository < Hanami::Repository
- associations do
- has_many :books
- end
-
- def create_with_books(data)
- assoc(:books).create(data)
- end
-
- def find_with_books(id)
- aggregate(:books).where(id: id).as(Author).one
- end
-end
-```
-
-We have defined [explicit methods](/guides/1.1/associations/overview#explicit-interface) only for the operations that we need for our model domain.
-In this way, we avoid to bloat `AuthorRepository` with dozen of unneeded methods.
-
-Let's create an author with a collection of books with a **single database operation**:
-
-```ruby
-repository = AuthorRepository.new
-
-author = repository.create_with_books(name: "Alexandre Dumas", books: [{title: "The Count of Montecristo"}])
- # => #1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC, :books=>[#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]}>
-
-author.id
- # => 1
-author.name
- # => "Alexandre Dumas"
-author.books
- # => [#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]
-```
-
-What happens if we load the author with `AuthorRepository#find`?
-
-```ruby
-author = repository.find(author.id)
- # => #1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>
-author.books
- # => nil
-```
-
-Because we haven't [explicitly loaded](/guides/1.1/associations/overview#explicit-loading) the associated records, `author.books` is `nil`.
-We can use the method that we have defined on before (`#find_with_books`):
-
-```ruby
-author = repository.find_with_books(author.id)
- # => #1, :name=>"Alexandre Dumas", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC, :books=>[#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]}>
-
-author.books
- # => [#1, :author_id=>1, :title=>"The Count of Montecristo", :created_at=>2016-11-15 09:19:38 UTC, :updated_at=>2016-11-15 09:19:38 UTC}>]
-```
-
-This time `author.books` has the collection of associated books.
-
-### Add and remove
-
-What if we need to add or remove books from an author?
-We need to define new methods to do so.
-
-```ruby
-# lib/bookshelf/repositories/author_repository.rb
-class AuthorRepository < Hanami::Repository
- # ...
-
- def add_book(author, data)
- assoc(:books, author).add(data)
- end
-
- def remove_book(author, id)
- assoc(:books, author).remove(id)
- end
-end
-```
-
-Let's add a book:
-
-```ruby
-book = repository.add_book(author, title: "The Three Musketeers")
-```
-
-And remove it:
-
-```ruby
-repository.remove_book(author, book.id)
-```
-
-### Querying
-
-An association can be [queried](/guides/1.1/models/sql-queries):
-
-```ruby
-# lib/bookshelf/repositories/author_repository.rb
-class AuthorRepository < Hanami::Repository
- # ...
-
- def books_count(author)
- assoc(:books, author).count
- end
-
- def on_sales_books_count(author)
- assoc(:books, author).where(on_sale: true).count
- end
-
- def find_book(author, id)
- book_for(author, id).one
- end
-
- def book_exists?(author, id)
- book_for(author, id).exists?
- end
-
- private
-
- def book_for(author, id)
- assoc(:books, author).where(id: id)
- end
-end
-```
-
-You can also run operations on top of these scopes:
-
-```ruby
-# lib/bookshelf/repositories/author_repository.rb
-class AuthorRepository < Hanami::Repository
- # ...
-
- def delete_on_sales_books(author)
- assoc(:books, author).where(on_sale: true).delete
- end
-end
-```
diff --git a/source/guides/1.1/associations/has-one.md b/source/guides/1.1/associations/has-one.md
deleted file mode 100644
index 56c7fa51f..000000000
--- a/source/guides/1.1/associations/has-one.md
+++ /dev/null
@@ -1,161 +0,0 @@
----
-title: "Guides - Associations: Has One"
-version: 1.1
----
-
-# Has One
-
-Also known as _one-to-one_, is an association between an entity (`User`) associated to one child entity (`Avatar`).
-
-## Setup
-
-```shell
-% bundle exec hanami generate model user
- create lib/bookshelf/entities/user.rb
- create lib/bookshelf/repositories/user_repository.rb
- create db/migrations/20171024083639_create_users.rb
- create spec/bookshelf/entities/user_spec.rb
- create spec/bookshelf/repositories/user_repository_spec.rb
-
-% bundle exec hanami generate model avatar
- create lib/bookshelf/entities/avatar.rb
- create lib/bookshelf/repositories/avatar_repository.rb
- create db/migrations/20171024083725_create_avatars.rb
- create spec/bookshelf/entities/avatar_spec.rb
- create spec/bookshelf/repositories/avatar_repository_spec.rb
-```
-
-Edit the migrations:
-
-```ruby
-# db/migrations/20171024083639_create_users.rb
-Hanami::Model.migration do
- change do
- create_table :users do
- primary_key :id
-
- column :name, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-```ruby
-# db/migrations/20171024083725_create_avatars.rb
-Hanami::Model.migration do
- change do
- create_table :avatars do
- primary_key :id
-
- foreign_key :user_id, :users, null: false, on_delete: :cascade
-
- column :url, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-Now we can prepare the database:
-
-```shell
-% bundle exec hanami db prepare
-```
-
-## Usage
-
-### Basic usage
-
-Let's edit `UserRepository` with the following code:
-
-```ruby
-# lib/bookshelf/repositories/user_repository.rb
-class UserRepository < Hanami::Repository
- associations do
- has_one :avatar
- end
-
- def create_with_avatar(data)
- assoc(:avatar).create(data)
- end
-
- def find_with_avatar(id)
- aggregate(:avatar).where(id: id).map_to(User).one
- end
-end
-```
-
-We have defined [explicit methods](/guides/1.1/associations/overview#explicit-interface) only for the operations that we need for our model domain.
-In this way, we avoid to bloat `UserRepository` with dozen of unneeded methods.
-
-Let's create an user with an avatar **single database operation**:
-
-```ruby
-repository = UserRepository.new
-
-user = repository.create_with_avatar(name: "Luca", avatar: { url: "https://avatars.test/luca.png" })
- # => #1, :name=>"Luca", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC, :avatar=>#1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>}>
-
-user.id
- # => 1
-
-user.name
- # => "Luca"
-
-user.avatar
- # => #1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>
-```
-
-What happens if we load the user with `UserRepository#find`?
-
-```ruby
-user = repository.find(user.id)
- # => #1, :name=>"Luca", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>
-user.avatar
- # => nil
-```
-
-Because we haven't [explicitly loaded](/guides/1.1/associations/overview#explicit-loading) the associated record, `user.avar` is `nil`.
-We can use the method that we have defined on before (`#find_with_avatar`):
-
-```ruby
-user = repository.find_with_avatar(user.id)
- # => #1, :name=>"Luca", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC, :avatar=>#1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>}>
-
-user.avatar
- # => #1, :user_id=>1, :url=>"https://avatars.test/luca.png", :created_at=>2017-10-24 08:44:27 UTC, :updated_at=>2017-10-24 08:44:27 UTC}>
-```
-
-This time `user.avatar` has the associated avatar.
-
-### Add, remove, update, and replace
-
-You can perform operations to add, remove, update, and replace the avatar:
-
-```ruby
-# lib/bookshelf/repositories/user_repository.rb
-class UserRepository < Hanami::Repository
- # ...
-
- def add_avatar(user, data)
- assoc(:avatar, user).add(data)
- end
-
- def remove_avatar(user)
- assoc(:avatar, user).delete
- end
-
- def update_avatar(user, data)
- assoc(:avatar, user).update(data)
- end
-
- def replace_avatar(user, data)
- assoc(:avatar, user).replace(data)
- end
-end
-```
diff --git a/source/guides/1.1/associations/overview.md b/source/guides/1.1/associations/overview.md
deleted file mode 100644
index 400957ba4..000000000
--- a/source/guides/1.1/associations/overview.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Guides - Associations Overview
-version: 1.1
----
-
-# Associations
-
-An association is a logical relationship between two entities.
-
-
- As of the current version, Hanami supports associations as an experimental feature only for the SQL adapter.
-
-
-## Design
-
-Because the association is made of data linked together in a database, we define associations in repositories.
-
-### Explicit Interface
-
-When we declare an association, that repository **does NOT** get any extra method to its public interface.
-This because Hanami wants to prevent to bloat in repositories by adding methods that are often never used.
-
-
- When we define an association, the repository doesn't get any extra public methods.
-
-
-If we need to create an author, contextually with a few books, we need to explicitly define a method to perform that operation.
-
-### Explicit Loading
-
-The same principle applies to read operations: if we want to eager load an author with the associated books, we need an explicit method to do so.
-
-If we don't explicitly load that books, then the resulting data will be `nil`.
-
-### No Proxy Loader
-
-Please remember that operations on associations are made via explicit repository methods.
-Hanami **does NOT** support by design, the following use cases:
-
- * `author.books` (to try to load books from the database)
- * `author.books.where(on_sale: true)` (to try to load _on sale_ books from the database)
- * `author.books << book` (to try to associate a book to the author)
- * `author.books.clear` (to try to unassociate the books from the author)
-
-Please remember that `author.books` is just an array, its mutation **won't be reflected in the database**.
-
-## Types Of Associations
-
- * [Has Many](/guides/1.1/associations/has-many)
- * [Belongs To](/guides/1.1/associations/belongs-to)
- * [Has One](/guides/1.1/associations/has-one)
- * [Has Many Through](/guides/1.1/associations/has-many-through)
diff --git a/source/guides/1.1/command-line/applications.md b/source/guides/1.1/command-line/applications.md
deleted file mode 100644
index e621ae00b..000000000
--- a/source/guides/1.1/command-line/applications.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: "Guides - Command Line: Applications"
-version: 1.1
----
-
-# Applications
-
-We can generate a new project via `hanami new`, followed by the name that we want to use.
-
-```shell
-% hanami new bookshelf
-```
-
-## Database
-
-The default database engine is SQLite.
-
-We can use the `--database` argument to let Hanami to generate code for a specific database.
-
-It supports:
-
- * `postgres`
- * `postgresql`
- * `sqlite` (default)
- * `sqlite3`
- * `mysql`
- * `mysql2`
-
-## Testing Framework
-
-The default testing framework is Minitest.
-
-We can use the `--test` argument to specify a different framework, from the list below:
-
- * `minitest` (default)
- * `rspec`
-
-## Template Engine
-
-The default template engine is ERB.
-
-We can use the `--template` argument to specify a different template engine, from the list below:
-
- * `erb` (default)
- * `haml`
- * `slim`
diff --git a/source/guides/1.1/command-line/assets.md b/source/guides/1.1/command-line/assets.md
deleted file mode 100644
index 8d7b864b6..000000000
--- a/source/guides/1.1/command-line/assets.md
+++ /dev/null
@@ -1,125 +0,0 @@
----
-title: "Guides - Command Line: Assets"
-version: 1.1
----
-
-# Assets
-
-We can manage assets via the command line.
-
-## Precompile
-
-This command is useful for **deployment** purposes.
-
-```shell
-% bundle exec hanami assets precompile
-```
-
-The first step it precompiles and copies all the assets from all the applications and third party gems under `public/assets/` directory.
-
-Then it [compress](/guides/1.1/assets/compressors) all the javascripts and stylesheets, in order to save browsers bandwidth.
-
-As last thing, it generates a copy of each asset, by appending its checksum to the file name.
-This trick makes assets cacheable by browsers.
-
-It generates a fingeprint manifest that lists all the assets and their checksum counterpart.
-
-```shell
-% cat public/assets.json
-{
- # ...
- "/assets/application.css":"/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css"
-}
-```
-
-This is used by assets helpers to resolve an asset name into a relative path.
-
-## Example
-
-Let's say we have a project with three applications: `admin`, `metrics` and `web`.
-
-```ruby
-# config/environment.rb
-# ...
-Hanami::Container.configure do
- mount Metrics::Application, at: '/metrics'
- mount Admin::Application, at: '/admin'
- mount Web::Application, at: '/'
-end
-```
-
-They have the following sources:
-
- * Admin: `apps/admin/assets`
- * Metrics: `apps/metrics/assets`
- * Web: `apps/web/assets`, `apps/web/vendor/assets`
-
-Furtermore, they all depend on Ember.js, which is distributed by an imaginary gem named `hanami-ember`.
-
-```shell
-% tree .
-βββ apps
-βΒ Β βββ admin
-βΒ Β βΒ Β βββ assets
-βΒ Β βΒ Β βΒ Β βββ js
-βΒ Β βΒ Β βΒ Β βββ application.js
-βΒ Β βΒ Β βΒ Β βββ zepto.js
-# ...
-βΒ Β βββ metrics
-βΒ Β βΒ Β βββ assets
-βΒ Β βΒ Β βΒ Β βββ javascripts
-βΒ Β βΒ Β βΒ Β βββ dashboard.js.es6
-# ...
-βΒ Β βββ web
-βΒ Β βββ assets
-βΒ Β βΒ Β βββ images
-βΒ Β βΒ Β βΒ Β βββ bookshelf.jpg
-βΒ Β βΒ Β βββ javascripts
-βΒ Β βΒ Β βββ application.js
-# ...
-βΒ Β βββ vendor
-βΒ Β βββ assets
-βΒ Β βββ javascripts
-βΒ Β βββ jquery.js
-# ...
-```
-
-When we run `hanami assets precompile` on our server, here's the output.
-
-```shell
-% tree public
-public
-βββ assets
-βΒ Β βββ admin
-βΒ Β βΒ Β βββ application-28a6b886de2372ee3922fcaf3f78f2d8.js
-βΒ Β βΒ Β βββ application.js
-βΒ Β βΒ Β βββ ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js
-βΒ Β βΒ Β βββ ember-source-e74117fc6ba74418b2601ffff9eb1568.js
-βΒ Β βΒ Β βββ ember-source.js
-βΒ Β βΒ Β βββ ember.js
-βΒ Β βΒ Β βββ zepto-ca736a378613d484138dec4e69be99b6.js
-βΒ Β βΒ Β βββ zepto.js
-βΒ Β βββ application-d1829dc353b734e3adc24855693b70f9.js
-βΒ Β βββ application.js
-βΒ Β βββ bookshelf-237ecbedf745af5a477e380f0232039a.jpg
-βΒ Β βββ bookshelf.jpg
-βΒ Β βββ ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js
-βΒ Β βββ ember-source-e74117fc6ba74418b2601ffff9eb1568.js
-βΒ Β βββ ember-source.js
-βΒ Β βββ ember.js
-βΒ Β βββ jquery-05277a4edea56b7f82a4c1442159e183.js
-βΒ Β βββ jquery.js
-βΒ Β βββ metrics
-βΒ Β βββ dashboard-7766a63ececc63a7a629bfb0666e9c62.js
-βΒ Β βββ dashboard.js
-βΒ Β βββ ember-b2d6de1e99c79a0e52cf5c205aa2e07a.js
-βΒ Β βββ ember-source-e74117fc6ba74418b2601ffff9eb1568.js
-βΒ Β βββ ember-source.js
-βΒ Β βββ ember.js
-βββ assets.json
-```
-
-
- The structure of the output directories in public/assets
, reflects the path prefix of each application. The default application named Web
, is mounted at /
, so the output directory is public/assets
and their base URL is /assets
(eg. /assets/application-28a6b886de2372ee3922fcaf3f78f2d8.js
).
- Simirarly, for an application Admin
mounted at /admin
, the assets will be placed under public/assets/admin
and reachable at /assets/admin/application-28a6b886de2372ee3922fcaf3f78f2d8.js
.
-
diff --git a/source/guides/1.1/command-line/database.md b/source/guides/1.1/command-line/database.md
deleted file mode 100644
index 5057b0bce..000000000
--- a/source/guides/1.1/command-line/database.md
+++ /dev/null
@@ -1,179 +0,0 @@
----
-title: "Guides - Command Line: Database"
-version: 1.1
----
-
-# Database
-
-We can manage our database via the command line.
-
-**The following commands can be only used with the SQL adapter and with the following databases:**
-
- * PostgreSQL
- * MySQL
- * SQLite3
-
-The [adapter](/guides/1.1/models/overview) is set in `config/environment.rb`.
-It uses an environment variable, defined in the `.env.*` files at the root of the project.
-
-## Create
-
-With `db create` we can create the database for the current environment.
-
-```shell
-% bundle exec hanami db create
-```
-
-To be able to run tests, test database has to be explicitly created
-
-```shell
-% HANAMI_ENV=test bundle exec hanami db create
-```
-
-In order to preserve production data, this command can't be run in the production environment.
-
-## Drop
-
-With `db drop` we can drop the existing database for the current environment.
-
-```shell
-% bundle exec hanami db drop
-```
-
-In order to preserve production data, this command can't be run in the production environment.
-
-## Migrate
-
-With `db migrate` we can run [migrations](/guides/1.1/migrations/overview) found in `db/migrations`.
-
-Given the following migrations:
-
-```shell
-% tree db/migrations
-db/migrations
-βββ 20171024081558_create_authors.rb
-βββ 20171024081617_create_books.rb
-βββ 20171024083639_create_users.rb
-βββ 20171024083725_create_avatars.rb
-βββ 20171024085712_create_stories.rb
-βββ 20171024085858_create_comments.rb
-
-0 directories, 6 files
-```
-
-We run `db migrate`, then the database _version_ becomes `20171024085858`, which is the maximum timestamp from the migrations above.
-
-```shell
-% bundle exec hanami db migrate # Migrates to max migration (20171024085858)
-```
-
-This command accepts an optional argument to specify the target version.
-For instance, if we want to **get back to** the changes from `20171024083639_create_users.rb`, we can migrate _**"down"**_.
-
-```shell
-% bundle exec hanami db migrate 20171024083639 # Migrates (down) to 20171024083639
-```
-
-**This command is available in ALL the environments and ALL the SQL databases.**
-
-## Rollback
-
-Rollback the database to a number of _steps_ _**"down"**_.
-
-We have the following migrations:
-
-```shell
-% tree db/migrations
-db/migrations
-βββ 20171024081558_create_authors.rb
-βββ 20171024081617_create_books.rb
-βββ 20171024083639_create_users.rb
-βββ 20171024083725_create_avatars.rb
-βββ 20171024085712_create_stories.rb
-βββ 20171024085858_create_comments.rb
-
-0 directories, 6 files
-```
-
-When we migrate the database:
-
-```shell
-% bundle exec hanami db migrate # Migrates to max migration (20171024085858)
-```
-
-We can rollback the last migration
-
-```shell
-% bundle exec hanami db rollback # Migrates (down) to 20171024085712
-```
-
-We can rollback the 3 migrations
-
-```shell
-% bundle exec hanami db rollback 3 # Migrates (down) to 20171024081617
-```
-
-## Prepare
-
-Prepares database for the current environment. This command can't be run in the production environment.
-
-When we run `db prepare` it:
-
- * Creates the database
- * Loads SQL dump (if any, see `db apply`)
- * Runs pending migrations
-
-```shell
-% bundle exec hanami db prepare
-```
-
-This command SHOULD be used as a database setup command.
-
-## Apply
-
-This is an experimental feature.
-When an application is developed after years, it accumulates a large number of migrations, this slows down database operations for development and test (CI).
-
-Because it does destructive changes to files under SCM, this is only allowed in development mode.
-
-When we run `db apply`, it:
-
- * Runs pending migrations
- * Dumps a fresh schema into `db/schema.sql`
- * Deletes all the migrations from `db/migrations`
-
-```shell
-% bundle exec hanami db apply
-```
-
-This command is available only in the development environment.
-
-## Version
-
-Prints current database version. Given the following migrations:
-
-```shell
-% tree db/migrations
-db/migrations
-βββ 20171024081558_create_authors.rb
-βββ 20171024081617_create_books.rb
-βββ 20171024083639_create_users.rb
-βββ 20171024083725_create_avatars.rb
-βββ 20171024085712_create_stories.rb
-βββ 20171024085858_create_comments.rb
-
-0 directories, 6 files
-```
-
-When we migrate the database:
-
-```shell
-% bundle exec hanami db migrate
-```
-
-We can then ask for the current version:
-
-```shell
-% bundle exec hanami db version
-20171024085858
-```
diff --git a/source/guides/1.1/command-line/destroy.md b/source/guides/1.1/command-line/destroy.md
deleted file mode 100644
index 0a52fe1a1..000000000
--- a/source/guides/1.1/command-line/destroy.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: "Guides - Command Line: Destroy"
-version: 1.1
----
-
-# Destroy
-
-Hanami has convenient [code generators](/guides/1.1/command-line/generators) to speed up our development process.
-If we commit a mistake, we can destroy what we just generated via `hanami destroy` command.
-
-## Applications
-
-With the Container architecture, we can have multiple Hanami applications running under `apps/`.
-We can [generate new applications](/guides/1.1/command-line/generators) for different components that we want to add to our project.
-
-To destroy one of them:
-
-```shell
-% bundle exec hanami destroy app admin
-```
-
-This removes an application named `Admin` under `apps/admin`.
-
-## Actions
-
-We can destroy an action along with the corresponding view, template, route and test code with one command.
-
-```shell
-% bundle exec hanami destroy action web books#show
-```
-
-The first argument, `web`, is the name of the target application in a Container architecture.
-**It must be omitted if used within an Application architecture:**
-
-```shell
-% bundle exec hanami destroy action books#show
-```
-
-The argument `books#show` is the name of the controller and the action separated by the number sign (`#`).
-
-## Models
-
-We can destroy a model.
-
-```shell
-% bundle exec hanami destroy model book
-```
-
-It removes an entity with the corresponding repository and test code.
-
-## Migrations
-
-We can destroy a migration.
-
-```shell
-% bundle exec hanami destroy migration create_books
-```
-
-It deletes the migration with the corresponding name (eg. `db/migrations/20150621181347_create_books.rb`).
-
-## Mailers
-
-We can destroy a mailer.
-
-```shell
-% bundle exec hanami destroy mailer welcome
-```
-
-It removes the mailer, and the associated templates.
diff --git a/source/guides/1.1/command-line/generators.md b/source/guides/1.1/command-line/generators.md
deleted file mode 100644
index 5e010ddf6..000000000
--- a/source/guides/1.1/command-line/generators.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: "Guides - Command Line: Generators"
-version: 1.1
----
-
-# Generators
-
-Hanami has convenient code generators to speed up our development process.
-
-## Applications
-
-With Hanami architecture, we can have multiple Hanami applications running under `apps/`.
-The default application is called `Web` and lives under `apps/web`.
-
-We can generate new applications for different components that we want to add to our project.
-
-```shell
-% bundle exec hanami generate app admin
-```
-
-This generates an application named `Admin` under `apps/admin`.
-
-## Actions
-
-Generate an action along with the corresponding view, template, route and test code with one command.
-
-```shell
-% bundle exec hanami generate action web books#show
-```
-
-The first argument, `web`, is the name of the target application in a Hanami project.
-
-The argument `books#show` is the name of the controller and the action separated by the number sign (`#`).
-
-If you wish to generate only the action, without the view and template, you can do that by using the `--skip-view`.
-
-```shell
-% bundle exec hanami generate action web books#show --skip-view
-```
-
-If you wish to generate action with specific method, you can do that by using the `--method`.
-
-```shell
-% bundle exec hanami generate action web books#create --method=post
-```
-
-### Route
-
-The generated route is named after the controller name.
-
-```ruby
-# apps/web/config/routes.rb
-get '/books', to: 'books#show'
-```
-
-If we want to customize the route URL, without editing our routes file, we can specify a `--url` argument.
-
-```shell
-% bundle exec hanami generate action web books#show --url=/books/:id
-```
-
-This will generate the following route:
-
-```ruby
-# apps/web/config/routes.rb
-get '/books/:id', to: 'books#show'
-```
-
-The default HTTP method is `GET`, except for actions named:
-
-- `create`, which will use `POST`
-- `update`, which will use `PATCH`
-- `destroy`, which will use `DELETE`
-
-This should help you route using [RESTful resources](/guides/1.1/routing/restful-resources).
-
-You can also set the HTTP method by specifying a `--method` argument when calling `hanami generate action`.
-
-## Models
-
-Generate an entity and a repository with a single command
-
-```shell
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create db/migrations/20170213123250_create_books.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-It generates an entity with the corresponding repository, migration, and tests.
-
-The migration will already contain the code for the creation of the table, the primary key and the timestamps:
-
-```ruby
-# db/migrations/20170213123250_create_books.rb
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-## Migrations
-
-Generate a database migration
-
-```shell
-% bundle exec hanami generate migration create_books
- create db/migrations/20161112113203_create_books.rb
-```
-
-It generates an empty migration with the UTC timestamp and the name we have specified: `db/migrations/20161112113203_create_books.rb`.
-
-## Mailers
-
-Generate a mailer
-
-```shell
-% bundle exec hanami generate mailer welcome
-```
-
-It creates the following files:
-
-```shell
-% tree lib/
-lib
-βββ bookshelf
-βΒ Β # ...
-βΒ Β βββ mailers
-βΒ Β βΒ Β βββ templates
-βΒ Β βΒ Β βΒ Β βββ welcome.html.erb
-βΒ Β βΒ Β βΒ Β βββ welcome.txt.erb
-βΒ Β βΒ Β βββ welcome.rb # Mailers::Welcome
-# ...
-```
-
-## Secret
-
-Generate a HTTP sessions secret for an application.
-
-```shell
-% bundle exec hanami generate secret web
-Set the following environment variable to provide the secret token:
-WEB_SESSIONS_SECRET="a6aa65a71538a56faffe1b1c9e96c0dc600de5dd14172f03c35cc48c3b27affe"
-```
diff --git a/source/guides/1.1/command-line/plugins.md b/source/guides/1.1/command-line/plugins.md
deleted file mode 100644
index 17ce270da..000000000
--- a/source/guides/1.1/command-line/plugins.md
+++ /dev/null
@@ -1,30 +0,0 @@
----
-title: "Guides - Command Line: Plugins"
-version: 1.1
----
-
-# Plugins
-
-Hanami has a convenient way to load commands from third party gems, so if you want to add a Hanami compatible gem, you only have to add it inside your project's `Gemfile` in a group called `:plugins`.
-
-Imagine you want to use a fictional gem called `hanami-webpack` and this gem provides several generators, the only thing you need to do, it's add it in the Gemfile in `:plugins` group:
-
-```ruby
-group :plugins do
- gem "hanami-webpack"
-end
-```
-
-After calling hanami webpack command inside your project:
-
-```shell
-% bundle exec hanami webpack
-```
-
-You can see the new commands that `hanami-webpack` provides:
-
-```shell
-hanami webpack install
-```
-
-If you call this command, the fictional gem will install webpack in your project.
diff --git a/source/guides/1.1/command-line/routes.md b/source/guides/1.1/command-line/routes.md
deleted file mode 100644
index 394b53f94..000000000
--- a/source/guides/1.1/command-line/routes.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: "Guides - Command Line: Routes"
-version: 1.1
----
-
-# Routes
-
-In order to print the routes defined by all the applications, use:
-
-```
-% bundle exec hanami routes
-
- GET, HEAD / Web::Controllers::Home::Index
- books GET, HEAD /books Web::Controllers::Books::Index
- new_books GET, HEAD /books/new Web::Controllers::Books::New
- books POST /books Web::Controllers::Books::Create
- books GET, HEAD /books/:id Web::Controllers::Books::Show
- edit_books GET, HEAD /books/:id/edit Web::Controllers::Books::Edit
- books PATCH /books/:id Web::Controllers::Books::Update
- books DELETE /books/:id Web::Controllers::Books::Destroy
- new_account GET, HEAD /account/new Web::Controllers::Account::New
- account POST /account Web::Controllers::Account::Create
- account GET, HEAD /account Web::Controllers::Account::Show
- edit_account GET, HEAD /account/edit Web::Controllers::Account::Edit
- account PATCH /account Web::Controllers::Account::Update
- account DELETE /account Web::Controllers::Account::Destroy
-```
diff --git a/source/guides/1.1/command-line/version.md.erb b/source/guides/1.1/command-line/version.md.erb
deleted file mode 100644
index 9220f5741..000000000
--- a/source/guides/1.1/command-line/version.md.erb
+++ /dev/null
@@ -1,23 +0,0 @@
----
-title: "Guides - Command Line: Version"
-version: 1.1
----
-
-# Version
-
-By running `hanami version` we can see the current version of the framework that we are using.
-
-```shell
-% bundle exec hanami version
-v<%= hanami_version %>
-```
-
-There are also `--version` and `-v` aliases.
-
-```shell
-% bundle exec hanami --version
-v<%= hanami_version %>
-
-% bundle exec hanami -v
-v<%= hanami_version %>
-```
diff --git a/source/guides/1.1/entities/custom-schema.md b/source/guides/1.1/entities/custom-schema.md
deleted file mode 100644
index c7e66c333..000000000
--- a/source/guides/1.1/entities/custom-schema.md
+++ /dev/null
@@ -1,155 +0,0 @@
----
-title: "Guides - Entities: Custom Schema"
-version: 1.1
----
-
-# Custom Schema
-
-We can take data integrity a step further: we can **optionally** define our own entity internal schema.
-
-
- Custom schema is optional for SQL databases, while it's mandatory for entities without a database table, or while using with a non-SQL database.
-
-
-
- Custom schema takes precedence over automatic schema. If we use custom schema, we need to manually add all the new columns from the corresponding SQL database table.
-
-
-## Default mode
-
-```ruby
-# lib/bookshelf/entities/user.rb
-class User < Hanami::Entity
- EMAIL_FORMAT = /\@/
-
- attributes do
- attribute :id, Types::Int
- attribute :name, Types::String
- attribute :email, Types::String.constrained(format: EMAIL_FORMAT)
- attribute :age, Types::Int.constrained(gt: 18)
- attribute :codes, Types::Collection(Types::Coercible::Int)
- attribute :comments, Types::Collection(Comment)
- attribute :created_at, Types::Time
- attribute :updated_at, Types::Time
- end
-end
-```
-
-Let's instantiate it with proper values:
-
-```ruby
-user = User.new(name: "Luca", age: 35, email: "luca@hanami.test")
-
-user.name # => "Luca"
-user.age # => 35
-user.email # => "luca@hanami.test"
-user.codes # => nil
-user.comments # => nil
-```
-
----
-
-It can coerce values:
-
-```ruby
-user = User.new(codes: ["123", "456"])
-user.codes # => [123, 456]
-```
-
-Other entities can be passed as concrete instance:
-
-```ruby
-user = User.new(comments: [Comment.new(text: "cool")])
-user.comments
- # => [#"cool"}>]
-```
-
-Or as data:
-
-```ruby
-user = User.new(comments: [{text: "cool"}])
-user.comments
- # => [#"cool"}>]
-```
-
----
-
-It enforces **data integrity** via exceptions:
-
-```ruby
-User.new(email: "foo") # => TypeError: "foo" (String) has invalid type for :email
-User.new(comments: [:foo]) # => TypeError: :foo must be coercible into Comment
-```
-
-## Strict mode
-
-```ruby
-# lib/bookshelf/entities/user.rb
-class User < Hanami::Entity
- EMAIL_FORMAT = /\@/
-
- attributes :strict do
- attribute :id, Types::Strict::Int
- attribute :name, Types::Strict::String
- attribute :email, Types::Strict::String.constrained(format: EMAIL_FORMAT)
- attribute :age, Types::Strict::Int.constrained(gt: 18)
- end
-end
-```
-
-Let's instantiate it with proper values:
-
-```ruby
-user = User.new(id: 1, name: "Luca", age: 35, email: "luca@hanami.test")
-
-user.id # => 1
-user.name # => "Luca"
-user.age # => 35
-user.email # => "luca@hanami.test"
-```
-
----
-
-It cannot be instantiated with missing keys
-
-```ruby
-User.new
- # => ArgumentError: :id is missing in Hash input
-```
-
-```ruby
-User.new(id: 1, name: "Luca", age: 35)
- # => ArgumentError: :email is missing in Hash input
-```
-
-Or with `nil`:
-
-```ruby
-User.new(id: 1, name: nil, age: 35, email: "luca@hanami.test")
- # => TypeError: nil (NilClass) has invalid type for :name violates constraints (type?(String, nil) failed)
-```
-
----
-
-It accepts strict values and it doesn't attempt to coerce:
-
-```ruby
-User.new(id: "1", name: "Luca", age: 35, email: "luca@hanami.test")
- # => TypeError: "1" (String) has invalid type for :id violates constraints (type?(Integer, "1") failed)
-```
-
----
-
-It enforces **data integrity** via exceptions:
-
-```ruby
-User.new(id: 1, name: "Luca", age: 1, email: "luca@hanami.test")
- # => TypeError: 1 (Integer) has invalid type for :age violates constraints (gt?(18, 1) failed)
-
-User.new(id: 1, name: "Luca", age: 35, email: "foo")
- # => TypeError: "foo" (String) has invalid type for :email violates constraints (format?(/\@/, "foo") failed)
-```
-
----
-
-**Learn more about data types in the [dedicated article](/guides/1.1/entities/data-types).**
diff --git a/source/guides/1.1/entities/data-types.md b/source/guides/1.1/entities/data-types.md
deleted file mode 100644
index ea2daf4c2..000000000
--- a/source/guides/1.1/entities/data-types.md
+++ /dev/null
@@ -1,90 +0,0 @@
----
-title: "Guides - Entities: Data Types"
-version: 1.1
----
-
-# Data Types
-
-Data types are available for custom [entities schema](/guides/1.1/entities/custom-schema), which are *completely optional*.
-
-We have 5 data types:
-
- * **Definition** - base type definition
- * **Strict** - strict type with primitive type check
- * **Coercible** - type with constructor that applies a coercion to given input
- * **Form** - type with constructor that applies a non-strict coercion, specific to HTTP params
- * **JSON** - type with constructor that applies a non-strict coercion, specific to JSON
-
-## Definition
-
- * `Types::Nil`
- * `Types::String`
- * `Types::Symbol`
- * `Types::Int`
- * `Types::Float`
- * `Types::Decimal`
- * `Types::Class`
- * `Types::Bool`
- * `Types::True`
- * `Types::False`
- * `Types::Date`
- * `Types::DateTime`
- * `Types::Time`
- * `Types::Array`
- * `Types::Hash`
-
-## Strict
-
- * `Types::Strict::Nil`
- * `Types::Strict::String`
- * `Types::Strict::Symbol`
- * `Types::Strict::Int`
- * `Types::Strict::Float`
- * `Types::Strict::Decimal`
- * `Types::Strict::Class`
- * `Types::Strict::Bool`
- * `Types::Strict::True`
- * `Types::Strict::False`
- * `Types::Strict::Date`
- * `Types::Strict::DateTime`
- * `Types::Strict::Time`
- * `Types::Strict::Array`
- * `Types::Strict::Hash`
-
-## Coercible
-
- * `Types::Coercible::String`
- * `Types::Coercible::Int`
- * `Types::Coercible::Float`
- * `Types::Coercible::Decimal`
- * `Types::Coercible::Array`
- * `Types::Coercible::Hash`
-
-## Form
-
- * `Types::Form::Nil`
- * `Types::Form::Int`
- * `Types::Form::Float`
- * `Types::Form::Decimal`
- * `Types::Form::Bool`
- * `Types::Form::True`
- * `Types::Form::False`
- * `Types::Form::Date`
- * `Types::Form::DateTime`
- * `Types::Form::Time`
- * `Types::Form::Array`
- * `Types::Form::Hash`
-
-## JSON
-
- * `Types::Json::Nil`
- * `Types::Json::Decimal`
- * `Types::Json::Date`
- * `Types::Json::DateTime`
- * `Types::Json::Time`
- * `Types::Json::Array`
- * `Types::Json::Hash`
-
----
-
-Hanami model data types are based on `dry-types` gem. Learn more at: [http://dry-rb.org/gems/dry-types](http://dry-rb.org/gems/dry-types)
diff --git a/source/guides/1.1/entities/overview.md b/source/guides/1.1/entities/overview.md
deleted file mode 100644
index e2616e70b..000000000
--- a/source/guides/1.1/entities/overview.md
+++ /dev/null
@@ -1,101 +0,0 @@
----
-title: Guides - Entities Overview
-version: 1.1
----
-
-# Entities
-
-An entity is domain object that is defined by its identity.
-
-See ["Domain Driven Design" by Eric Evans](https://en.wikipedia.org/wiki/Domain-driven_design#Building_blocks).
-
-An entity is at the core of an application, where the part of the domain logic is implemented.
-It's a small, cohesive object that expresses coherent and meaningful behaviors.
-
-It deals with one and only one responsibility that is pertinent to the
-domain of the application, without caring about details such as persistence
-or validations.
-
-This simplicity of design allows developers to focus on behaviors, or
-message passing if you will, which is the quintessence of Object Oriented Programming.
-
-## Entity Schema
-
-Internally, an entity holds a schema of the attributes, made of their names and types.
-The role of a schema is to whitelist the data used during the initialization, and to enforce data integrity via coercions or exceptions.
-
-We'll see concrete examples in a second.
-
-### Automatic Schema
-
-When using a SQL database, this is derived automatically from the table definition.
-
-Imagine to have the `books` table defined as:
-
-```sql
-CREATE TABLE books (
- id integer NOT NULL,
- title text,
- created_at timestamp without time zone,
- updated_at timestamp without time zone
-);
-```
-
-This is the corresponding entity `Book`.
-
-```ruby
-# lib/bookshelf/entities/book.rb
-class Book < Hanami::Entity
-end
-```
-
----
-
-Let's instantiate it with proper values:
-
-```ruby
-book = Book.new(title: "Hanami")
-
-book.title # => "Hanami"
-book.created_at # => nil
-```
-
-The `created_at` attribute is `nil` because it wasn't present when we have instantiated `book`.
-
----
-
-It ignores unknown attributes:
-
-```ruby
-book = Book.new(unknown: "value")
-
-book.unknown # => NoMethodError
-book.foo # => NoMethodError
-```
-
-It raises a `NoMethodError` both for `unknown` and `foo`, because they aren't part of the internal schema.
-
----
-
-It can coerce values:
-
-```ruby
-book = Book.new(created_at: "Sun, 13 Nov 2016 09:41:09 GMT")
-
-book.created_at # => 2016-11-13 09:41:09 UTC
-book.created_at.class # => Time
-```
-
-An entity tries as much as it cans to coerce values according to the internal schema.
-
----
-
-It enforces **data integrity** via exceptions:
-
-```ruby
-Book.new(created_at: "foo") # => ArgumentError
-```
-
-If we use this feature, in combination with [database constraints](/guides/1.1/migrations/create-table#constraints) and validations, we can guarantee a **strong** level of **data integrity** for our projects.
-
-**You can set your own set of attributes via [custom schema](/guides/1.1/entities/custom-schema).**
diff --git a/source/guides/1.1/getting-started.md b/source/guides/1.1/getting-started.md
deleted file mode 100644
index 89cd00372..000000000
--- a/source/guides/1.1/getting-started.md
+++ /dev/null
@@ -1,1101 +0,0 @@
----
-title: Guides - Getting Started
-version: 1.1
----
-
-# Getting Started
-
-
-
- Hello. If you're reading this page, it's very likely that you want to learn more about Hanami.
- That's great, congrats! If you're looking for new ways to build maintainable, secure, faster and testable web applications, you're in good hands.
-
-
-
- Hanami is built for people like you.
-
-
-
- I warn you that whether you're a total beginner or an experienced developer this learning process can be hard .
- Over time, we build expectations about how things should be, and it can be painful to change. But without change, there is no challenge and without challenge, there is no growth.
-
-
-
- Sometimes a feature doesn't look right, that doesn't mean it's you.
- It can be a matter of formed habits, a design fallacy or even a bug.
-
-
-
- Myself and the rest of the Community are putting best efforts to make Hanami better every day.
-
-
-
- In this guide we will set up our first Hanami project and build a simple bookshelf web application.
- We'll touch on all the major components of Hanami framework, all guided by tests.
-
-
-
- If you feel alone, or frustrated, don't give up, jump in our chat and ask for help.
- There will be someone more than happy to talk with you.
-
-
-
- Enjoy,
- Luca Guidi
- Hanami creator
-
-
-
-
-
-
-## Prerequisites
-
-Before we get started, let's get some prerequisites out of the way.
-First, we're going to assume a basic knowledge of developing web applications.
-
-You should also be familiar with [Bundler](http://bundler.io), [Rake](http://rake.rubyforge.org), working with a terminal and building apps using the [Model, View, Controller](https://en.wikipedia.org/wiki/Model%E2%80%93view%E2%80%93controller) paradigm.
-
-Lastly, in this guide we'll be using a [SQLite](https://sqlite.org/) database.
-If you want to follow along, make sure you have a working installation of Ruby 2.3+ and SQLite 3+ on your system.
-
-## Create a New Hanami Project
-
-To create a new Hanami project, we need to install the Hanami gem from Rubygems.
-Then we can use the new `hanami` executable to generate a new project:
-
-```
-% gem install hanami
-% hanami new bookshelf
-```
-
-
- By default, the project will be setup to use a SQLite database. For real-world projects, you can specify your engine:
-
- % hanami new bookshelf --database=postgres
- Β
-
-
-This will create a new directory `bookshelf` in our current location.
-Let's see what it contains:
-
-```
-% cd bookshelf
-% tree -L 1
-.
-βββ Gemfile
-βββ Rakefile
-βββ apps
-βββ config
-βββ config.ru
-βββ db
-βββ lib
-βββ public
-βββ spec
-
-6 directories, 3 files
-```
-
-Here's what we need to know:
-
-* `Gemfile` defines our Rubygems dependencies (using Bundler).
-* `Rakefile` describes our Rake tasks.
-* `apps` contains one or more web applications compatible with Rack.
- Here we can find the first generated Hanami application called `Web`.
- It's the place where we find our controllers, views, routes and templates.
-* `config` contains configuration files.
-* `config.ru` is for Rack servers.
-* `db` contains our database schema and migrations.
-* `lib` contains our business logic and domain model, including entities and repositories.
-* `public` will contain compiled static assets.
-* `spec` contains our tests.
-
-Go ahead and install our gem dependency with Bundler; then we can launch a development server:
-
-```
-% bundle install
-% bundle exec hanami server
-```
-
-And... bask in the glory of your first Hanami project at
-[http://localhost:2300](http://localhost:2300)! We should see a screen similar to this:
-
-
-
-## Hanami Architecture
-
-Hanami architecture **can host several Hanami (and Rack) applications in the same Ruby process**.
-
-These applications live under `apps/`.
-Each of them can be a component of our product, such as the user facing web interface, the admin pane, metrics, HTTP API etc..
-
-All these parts are a _delivery mechanism_ to the business logic that lives under `lib/`.
-This is the place where our models are defined, and interact with each other to compose the **features** that our product provides.
-
-Hanami architecture is heavily inspired by [Clean Architecture](https://blog.8thlight.com/uncle-bob/2012/08/13/the-clean-architecture.html).
-
-## Writing Our First Test
-
-The opening screen we see when we point our browser at our app, is a
-default page which is displayed when there are no routes defined.
-
-Hanami encourages [Behavior Driven Development](https://en.wikipedia.org/wiki/Behavior-driven_development) (BDD) as a way to write web applications.
-In order to get our first custom page to display, we'll write a high-level feature test:
-
-```ruby
-# spec/web/features/visit_home_spec.rb
-require 'features_helper'
-
-describe 'Visit home' do
- it 'is successful' do
- visit '/'
-
- page.body.must_include('Bookshelf')
- end
-end
-```
-
-Note that, although Hanami is ready for a Behavior Driven Development workflow out of the box, **it is in no way bound to any particular testing framework** -- nor does it come with special integrations or libraries.
-
-We'll go with [Minitest](https://github.com/seattlerb/minitest) here (which is the default), but we can use [RSpec](http://rspec.info) by creating the project with `--test=rspec` option.
-Hanami will then generate helpers and stub files for it.
-
-
- Please check .env.test in case you need to tweak the database URL.
-
-
-We have to migrate our schema in the test database by running:
-
-```shell
-% HANAMI_ENV=test bundle exec hanami db prepare
-```
-
-As you can see, we have set `HANAMI_ENV` environment variable to instruct our command about the environment to use.
-
-### Following a Request
-
-Now we have a test, we can see it fail:
-
-```
-% bundle exec rake test
-Run options: --seed 44759
-
-# Running:
-
-F
-
-Finished in 0.018611s, 53.7305 runs/s, 53.7305 assertions/s.
-
- 1) Failure:
-Homepage#test_0001_is successful [/Users/hanami/bookshelf/spec/web/features/visit_home_spec.rb:6]:
-Expected "\n\n \n Not Found \n \n \n Not Found \n \n\n" to include "Bookshelf".
-
-1 runs, 1 assertions, 1 failures, 0 errors, 0 skips
-```
-
-Now let's make it pass.
-Lets add the code required to make this test pass, step-by-step.
-
-The first thing we need to add is a route:
-
-```ruby
-# apps/web/config/routes.rb
-root to: 'home#index'
-```
-
-We pointed our application's root URL to the `index` action of the `home` controller (see the [routing guide](/guides/1.1/routing/overview) for more information).
-Now we can create the index action.
-
-```ruby
-# apps/web/controllers/home/index.rb
-module Web::Controllers::Home
- class Index
- include Web::Action
-
- def call(params)
- end
- end
-end
-```
-
-This is an empty action that doesn't implement any business logic.
-Each action has a corresponding view, which is a Ruby object and needs to be added in order to complete the request.
-
-```ruby
-# apps/web/views/home/index.rb
-module Web::Views::Home
- class Index
- include Web::View
- end
-end
-```
-
-...which, in turn, is empty and does nothing more than render its template.
-This is the file we need to edit in order to make our test pass. All we need to do is add the bookshelf heading.
-
-```erb
-# apps/web/templates/home/index.html.erb
-Bookshelf
-```
-
-Save your changes, run your test again and it now passes. Great!
-
-```shell
-Run options: --seed 19286
-
-# Running:
-
-.
-
-Finished in 0.011854s, 84.3600 runs/s, 168.7200 assertions/s.
-
-1 runs, 2 assertions, 0 failures, 0 errors, 0 skips
-```
-
-## Generating New Actions
-
-Let's use our new knowledge about the major Hanami components to add a new action.
-The purpose of our Bookshelf project is to manage books.
-
-We'll store books in our database and let the user manage them with our project.
-A first step would be to show a listing of all the books in our system.
-
-Let's write a new feature test describing what we want to achieve:
-
-```ruby
-# spec/web/features/list_books_spec.rb
-require 'features_helper'
-
-describe 'List books' do
- it 'displays each book on the page' do
- visit '/books'
-
- within '#books' do
- assert page.has_css?('.book', count: 2), 'Expected to find 2 books'
- end
- end
-end
-```
-
-The test is simple enough, and fails because the URL `/books` is not currently recognised in our application. We'll create a new controller action to fix that.
-
-### Hanami Generators
-
-Hanami ships with various **generators** to save on typing some of the code involved in adding new functionality.
-In our terminal, enter:
-
-```
-% bundle exec hanami generate action web books#index
-```
-
-This will generate a new action _index_ in the _books_ controller of the _web_ application.
-It gives us an empty action, view and template; it also adds a default route to `apps/web/config/routes.rb`:
-
-```ruby
-get '/books', to: 'books#index'
-```
-
-If you're using ZSH, you may get `zsh: no matches found: books#index`. In that case, you can use:
-```
-% hanami generate action web books/index
-```
-
-To make our test pass, we need to edit our newly generated template file in `apps/web/templates/books/index.html.erb`:
-
-```html
-Bookshelf
-All books
-
-
-
-
Patterns of Enterprise Application Architecture
-
by Martin Fowler
-
-
-
-
Test Driven Development
-
by Kent Beck
-
-
-```
-
-Save your changes and see your tests pass! The output will also contain a skipped test. This is due to an autogenerated test in `spec/web/views/books/index_spec.rb`.
-
-The terminology of controllers and actions might be confusing, so let's clear this up: actions form the basis of our Hanami applications; controllers are mere modules that group several actions together.
-So while the "controller" is _conceptually_ present in our project, in practice we only deal with actions.
-
-We've used a generator to create a new endpoint in our application.
-But one thing you may have noticed is that our new template contains the same `` as our `home/index.html.erb` template.
-Let's fix that.
-
-### Layouts
-
-To avoid repeating ourselves in every single template, we can use a layout.
-Open up the file `apps/web/templates/application.html.erb` and edit it to look like this:
-
-```rhtml
-
-
-
- Bookshelf
- <%= favicon %>
-
-
- Bookshelf
- <%= yield %>
-
-
-```
-
-Now you can remove the duplicate lines from the other templates. Let's run the tests again to check that everything worked fine.
-
-A **layout** is like any other template, but it is used to wrap your regular templates.
-The `yield` line is replaced with the contents of our regular template.
-It's the perfect place to put our repeating headers and footers.
-
-## Modeling Our Data With Entities
-
-Hard-coding books in our templates is, admittedly, kind of cheating.
-Let's add some dynamic data to our application.
-
-We'll store books in our database and display them on our page.
-To do so, we need a way to read and write to our database.
-Enter entities and repositories:
-
-* an **entity** is a domain object (eg. `Book`) uniquely identified by its identity.
-* a **repository** mediates between entities and the persistence layer.
-
-Entities are totally unaware of the database.
-This makes them **lightweight** and **easy to test**.
-
-For this reason we need a repository to persist the data that a `Book` depends on.
-Read more about entities and repositories in the [models guide](/guides/1.1/models/overview).
-
-Hanami ships with a generator for models, so let's use it to create a `Book` entity and the corresponding repository:
-
-```
-% bundle exec hanami generate model book
-create lib/bookshelf/entities/book.rb
-create lib/bookshelf/repositories/book_repository.rb
-create db/migrations/20161115110038_create_books.rb
-create spec/bookshelf/entities/book_spec.rb
-create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-The generator gives us an entity, a repository, a migration, and accompanying test files.
-
-### Migrations To Change Our Database Schema
-
-Let's modify the generated migration (the path to the migration will differ for you, because it contains a timestamp) to include `title` and `author` fields:
-
-```ruby
-# db/migrations/20161115110038_create_books.rb
-
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
-
- column :title, String, null: false
- column :author, String, null: false
-
- column :created_at, DateTime, null: false
- column :updated_at, DateTime, null: false
- end
- end
-end
-```
-
-Hanami provides a DSL to describe changes to our database schema. You can read more
-about how migrations work in the [migrations' guide](/guides/1.1/migrations/overview).
-
-In this case, we define a new table with columns for each of our entities' attributes.
-Let's prepare our database for the development and test environments:
-
-```
-% bundle exec hanami db prepare
-% HANAMI_ENV=test bundle exec hanami db prepare
-```
-
-### Working With Entities
-
-An entity is something really close to a plain Ruby object.
-We should focus on the behaviors that we want from it and only then, how to save it.
-
-For now, we keep the generated entity class:
-
-```ruby
-# lib/bookshelf/entities/book.rb
-class Book < Hanami::Entity
-end
-```
-
-This class will generate getters and setters for each attribute which we pass to initialize params.
-We can verify it all works as expected with a unit test:
-
-```ruby
-# spec/bookshelf/entities/book_spec.rb
-require_relative '../../spec_helper'
-
-describe Book do
- it 'can be initialized with attributes' do
- book = Book.new(title: 'Refactoring')
- book.title.must_equal 'Refactoring'
- end
-end
-```
-
-### Using Repositories
-
-Now we are ready to play around with our repository.
-We can use Hanami's `console` command to launch IRb with our application pre-loaded, so we can use our objects:
-
-```
-% bundle exec hanami console
->> repository = BookRepository.new
-=> => #
->> repository.all
-=> []
->> book = repository.create(title: 'TDD', author: 'Kent Beck')
-=> #1, :title=>"TDD", :author=>"Kent Beck", :created_at=>2016-11-15 11:11:38 UTC, :updated_at=>2016-11-15 11:11:38 UTC}>
->> repository.find(book.id)
-=> #1, :title=>"TDD", :author=>"Kent Beck", :created_at=>2016-11-15 11:11:38 UTC, :updated_at=>2016-11-15 11:11:38 UTC}>
-```
-
-Hanami repositories have methods to load one or more entities from our database; and to create and update existing records.
-The repository is also the place where you would define new methods to implement custom queries.
-
-To recap, we've seen how Hanami uses entities and repositories to model our data.
-Entities represent our behavior, while repositories use mappings to translate our entities to our data store.
-We can use migrations to apply changes to our database schema.
-
-### Displaying Dynamic Data
-
-With our new experience modelling data, we can get to work displaying dynamic data on our book listing page.
-Let's adjust the feature test we created earlier:
-
-```ruby
-# spec/web/features/list_books_spec.rb
-require 'features_helper'
-
-describe 'List books' do
- let(:repository) { BookRepository.new }
- before do
- repository.clear
-
- repository.create(title: 'PoEAA', author: 'Martin Fowler')
- repository.create(title: 'TDD', author: 'Kent Beck')
- end
-
- it 'displays each book on the page' do
- visit '/books'
-
- within '#books' do
- assert page.has_css?('.book', count: 2), 'Expected to find 2 books'
- end
- end
-end
-```
-
-We create the required records in our test and then assert the correct number of book classes on the page.
-When we run this test it should pass. If it does not pass, a likely reason is that the test database was not migrated.
-
-Now we can go change our template and remove the static HTML.
-Our view needs to loop over all available records and render them.
-Let's write a test to force this change in our view:
-
-```ruby
-# spec/web/views/books/index_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Views::Books::Index do
- let(:exposures) { Hash[books: []] }
- let(:template) { Hanami::View::Template.new('apps/web/templates/books/index.html.erb') }
- let(:view) { Web::Views::Books::Index.new(template, exposures) }
- let(:rendered) { view.render }
-
- it 'exposes #books' do
- view.books.must_equal exposures.fetch(:books)
- end
-
- describe 'when there are no books' do
- it 'shows a placeholder message' do
- rendered.must_include('There are no books yet.
')
- end
- end
-
- describe 'when there are books' do
- let(:book1) { Book.new(title: 'Refactoring', author: 'Martin Fowler') }
- let(:book2) { Book.new(title: 'Domain Driven Design', author: 'Eric Evans') }
- let(:exposures) { Hash[books: [book1, book2]] }
-
- it 'lists them all' do
- rendered.scan(/class="book"/).count.must_equal 2
- rendered.must_include('Refactoring')
- rendered.must_include('Domain Driven Design')
- end
-
- it 'hides the placeholder message' do
- rendered.wont_include('There are no books yet.
')
- end
- end
-end
-```
-
-We specify that our index page will show a simple placeholder message when there are no books to display; when there are, it lists every one of them.
-Note how rendering a view with some data is relatively straight-forward.
-Hanami is designed around simple objects with minimal interfaces that are easy to test in isolation, yet still work great together.
-
-Let's rewrite our template to implement these requirements:
-
-```erb
-# apps/web/templates/books/index.html.erb
-All books
-
-<% if books.any? %>
-
- <% books.each do |book| %>
-
-
<%= book.title %>
-
<%= book.author %>
-
- <% end %>
-
-<% else %>
- There are no books yet.
-<% end %>
-```
-
-If we run our feature test now, we'll see it fails β because our controller
-action does not actually [_expose_](/guides/1.1/actions/exposures) the books to our view. We can write a test for
-that change:
-
-```ruby
-# spec/web/controllers/books/index_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Controllers::Books::Index do
- let(:action) { Web::Controllers::Books::Index.new }
- let(:params) { Hash[] }
- let(:repository) { BookRepository.new }
-
- before do
- repository.clear
-
- @book = repository.create(title: 'TDD', author: 'Kent Beck')
- end
-
- it 'is successful' do
- response = action.call(params)
- response[0].must_equal 200
- end
-
- it 'exposes all books' do
- action.call(params)
- action.exposures[:books].must_equal [@book]
- end
-end
-```
-
-Writing tests for controller actions is basically two-fold: you either assert on the response object, which is a Rack-compatible array of status, headers and content; or on the action itself, which will contain exposures after we've called it.
-Now we've specified that the action exposes `:books`, we can implement our action:
-
-```ruby
-# apps/web/controllers/books/index.rb
-module Web::Controllers::Books
- class Index
- include Web::Action
-
- expose :books
-
- def call(params)
- @books = BookRepository.new.all
- end
- end
-end
-```
-
-By using the `expose` method in our action class, we can expose the contents of our `@books` instance variable to the outside world, so that Hanami can pass it to the view.
-That's enough to make all our tests pass again!
-
-```shell
-% bundle exec rake
-Run options: --seed 59133
-
-# Running:
-
-.........
-
-Finished in 0.042065s, 213.9543 runs/s, 380.3633 assertions/s.
-
-9 runs, 16 assertions, 0 failures, 0 errors, 0 skips
-```
-
-## Building Forms To Create Records
-
-One of the last remaining steps is to make it possible to add new books to the system.
-The plan is simple: we build a page with a form to enter details.
-
-When the user submits the form, we build a new entity, save it, and redirect the user back to the book listing.
-Here's that story expressed in a test:
-
-```ruby
-# spec/web/features/add_book_spec.rb
-require 'features_helper'
-
-describe 'Add a book' do
- after do
- BookRepository.new.clear
- end
-
- it 'can create a new book' do
- visit '/books/new'
-
- within 'form#book-form' do
- fill_in 'Title', with: 'New book'
- fill_in 'Author', with: 'Some author'
-
- click_button 'Create'
- end
-
- current_path.must_equal('/books')
- assert page.has_content?('New book')
- end
-end
-```
-
-### Laying The Foundations For A Form
-
-By now, we should be familiar with the working of actions, views and templates.
-
-We'll speed things up a little, so we can quickly get to the good parts.
-First, create a new action for our "New Book" page:
-
-```
-% bundle exec hanami generate action web books#new
-```
-
-This adds a new route to our app:
-
-```ruby
-# apps/web/config/routes.rb
-get '/books/new', to: 'books#new'
-```
-
-The interesting bit will be our new template, because we'll be using Hanami's form builder to construct a HTML form around our `Book` entity.
-
-### Using Form Helpers
-
-Let's use [form helpers](/guides/1.1/helpers/forms) to build this form in `apps/web/templates/books/new.html.erb`:
-
-```erb
-# apps/web/templates/books/new.html.erb
-Add book
-
-<%=
- form_for :book, '/books' do
- div class: 'input' do
- label :title
- text_field :title
- end
-
- div class: 'input' do
- label :author
- text_field :author
- end
-
- div class: 'controls' do
- submit 'Create Book'
- end
- end
-%>
-```
-
-We've added `` tags for our form fields, and wrapped each field in a
-container `` using Hanami's [HTML builder helper](/guides/1.1/helpers/html5).
-
-### Submitting Our Form
-
-To submit our form, we need yet another action.
-Let's create a `Books::Create` action:
-
-```
-% bundle exec hanami generate action web books#create
-```
-
-This adds a new route to our app:
-
-```ruby
-# apps/web/config/routes.rb
-post '/books', to: 'books#create'
-```
-
-### Implementing Create Action
-
-Our `books#create` action needs to do two things.
-Let's express them as unit tests:
-
-```ruby
-# spec/web/controllers/books/create_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Controllers::Books::Create do
- let(:action) { Web::Controllers::Books::Create.new }
- let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
- let(:repository) { BookRepository.new }
-
- before do
- repository.clear
- end
-
- it 'creates a new book' do
- action.call(params)
- book = repository.last
-
- book.id.wont_be_nil
- book.title.must_equal params.dig(:book, :title)
- end
-
- it 'redirects the user to the books listing' do
- response = action.call(params)
-
- response[0].must_equal 302
- response[1]['Location'].must_equal '/books'
- end
-end
-```
-
-Let's make these tests pass!
-We've already seen how we can write entities to our database, and we can use `redirect_to` to implement our redirection:
-
-```ruby
-# apps/web/controllers/books/create.rb
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- def call(params)
- BookRepository.new.create(params[:book])
-
- redirect_to '/books'
- end
- end
-end
-```
-
-This minimal implementation should suffice to make our tests pass.
-
-```shell
-% bundle exec rake
-Run options: --seed 63592
-
-# Running:
-
-...S.S.........
-
-Finished in 0.081961s, 183.0142 runs/s, 305.0236 assertions/s.
-
-15 runs, 23 assertions, 0 failures, 0 errors, 2 skips
-
-You have skipped tests. Run with --verbose for details.
-```
-
-Congratulations!
-
-### Securing Our Form With Validations
-
-Hold your horses! We need some extra measures to build a truly robust form.
-Imagine what would happen if the user were to submit the form without entering any values?
-
-We could fill our database with bad data or see an exception for data integrity violations.
-We clearly need a way of keeping invalid data out of our system!
-
-To express our validations in a test, we need to wonder: what _would_ happen if our validations failed?
-One option would be to re-render the `books#new` form, so we can give our users another shot at completing it correctly.
-Let's specify this behaviour as unit tests:
-
-```ruby
-# spec/web/controllers/books/create_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Controllers::Books::Create do
- let(:action) { Web::Controllers::Books::Create.new }
- let(:repository) { BookRepository.new }
-
- before do
- repository.clear
- end
-
- describe 'with valid params' do
- let(:params) { Hash[book: { title: 'Confident Ruby', author: 'Avdi Grimm' }] }
-
- it 'creates a book' do
- action.call(params)
- book = repository.last
-
- book.id.wont_be_nil
- book.title.must_equal params.dig(:book, :title)
- end
-
- it 'redirects the user to the books listing' do
- response = action.call(params)
-
- response[0].must_equal 302
- response[1]['Location'].must_equal '/books'
- end
- end
-
- describe 'with invalid params' do
- let(:params) { Hash[book: {}] }
-
- it 'returns HTTP client error' do
- response = action.call(params)
- response[0].must_equal 422
- end
-
- it 'dumps errors in params' do
- action.call(params)
- errors = action.params.errors
-
- errors.dig(:book, :title).must_equal ['is missing']
- errors.dig(:book, :author).must_equal ['is missing']
- end
- end
-end
-```
-
-Now our tests specify two alternative scenarios: our original happy path, and a new scenario in which validations fail.
-To make our tests pass, we need to implement validations.
-
-Although you can add validation rules to the entity, Hanami also allows you to define validation rules as close to the source of the input as possible, i.e. the action.
-Hanami controller actions can use the `params` class method to define acceptable incoming parameters.
-
-This approach both whitelists what params are used (others are discarded to prevent mass-assignment vulnerabilities from untrusted user input) _and_ adds rules to define what values are acceptable β in this case we've specified that the nested attributes for a book's title and author should be present.
-
-With our validations in place, we can limit our entity creation and redirection to cases where the incoming params are valid:
-
-```ruby
-# apps/web/controllers/books/create.rb
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- expose :book
-
- params do
- required(:book).schema do
- required(:title).filled(:str?)
- required(:author).filled(:str?)
- end
- end
-
- def call(params)
- if params.valid?
- @book = BookRepository.new.create(params[:book])
-
- redirect_to '/books'
- else
- self.status = 422
- end
- end
- end
-end
-```
-
-When the params are valid, the Book is created and the action redirects to a different URL.
-But when the params are not valid, what happens?
-
-First, the HTTP status code is set to
-[422 (Unprocessable Entity)](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes#422).
-Then the control will pass to the corresponding view, which needs to know which template to render.
-In this case `apps/web/templates/books/new.html.erb` will be used to render the form again.
-
-```ruby
-# apps/web/views/books/create.rb
-module Web::Views::Books
- class Create
- include Web::View
- template 'books/new'
- end
-end
-```
-
-This approach will work nicely because Hanami's form builder is smart enough to inspect the `params` in this action and populate the form fields with values found in the params.
-If the user fills in only one field before submitting, they are presented with their original input, saving them the frustration of typing it again.
-
-Run your tests again and see they are all passing again!
-
-### Displaying Validation Errors
-
-Rather than just shoving the user a form under their nose when something has gone wrong, we should give them a hint of what's expected of them. Let's adapt our form to show a notice about invalid fields.
-
-First, we expect a list of errors to be included in the page when `params` contains errors:
-
-```ruby
-# spec/web/views/books/new_spec.rb
-require_relative '../../../spec_helper'
-
-describe Web::Views::Books::New do
- let(:params) { OpenStruct.new(valid?: false, error_messages: ['Title must be filled', 'Author must be filled']) }
- let(:exposures) { Hash[params: params] }
- let(:template) { Hanami::View::Template.new('apps/web/templates/books/new.html.erb') }
- let(:view) { Web::Views::Books::New.new(template, exposures) }
- let(:rendered) { view.render }
-
- it 'displays list of errors when params contains errors' do
- rendered.must_include('There was a problem with your submission')
- rendered.must_include('Title must be filled')
- rendered.must_include('Author must be filled')
- end
-end
-```
-
-We should also update our feature spec to reflect this new behavior:
-
-```ruby
-# spec/web/features/add_book_spec.rb
-require 'features_helper'
-
-describe 'Add a book' do
- # Spec written earlier omitted for brevity
-
- it 'displays list of errors when params contains errors' do
- visit '/books/new'
-
- within 'form#book-form' do
- click_button 'Create'
- end
-
- current_path.must_equal('/books')
-
- assert page.has_content?('There was a problem with your submission')
- assert page.has_content?('Title must be filled')
- assert page.has_content?('Author must be filled')
- end
-end
-```
-
-In our template we can loop over `params.errors` (if there are any) and display a friendly message.
-Open up `apps/web/templates/books/new.html.erb` and add the following at the top of the file:
-
-```erb
-<% unless params.valid? %>
-
-
There was a problem with your submission
-
- <% params.error_messages.each do |message| %>
- <%= message %>
- <% end %>
-
-
-<% end %>
-```
-
-Run your tests again and see they are all passing again!
-
-```shell
-% bundle exec rake
-Run options: --seed 59940
-
-# Running:
-
-......S..........
-
-Finished in 0.188950s, 89.9707 runs/s, 179.9413 assertions/s.
-
-17 runs, 34 assertions, 0 failures, 0 errors, 1 skips
-
-You have skipped tests. Run with --verbose for details.
-```
-
-### Improving Our Use Of The Router
-
-The last improvement we are going to make, is in the use of our router.
-Open up the routes file for the "web" application:
-
-```ruby
-# apps/web/config/routes.rb
-post '/books', to: 'books#create'
-get '/books/new', to: 'books#new'
-get '/books', to: 'books#index'
-root to: 'home#index'
-```
-
-Hanami provides a convenient helper method to build these REST-style routes, that we can use to simplify our router a bit:
-
-```ruby
-root to: 'home#index'
-resources :books, only: [:index, :new, :create]
-```
-
-To get a sense of what routes are defined, now we've made this change, you can
-run `bundle exec hanami routes` on your command-line to inspect the end result:
-
-```
-% bundle exec hanami routes
- Name Method Path Action
-
- root GET, HEAD / Web::Controllers::Home::Index
- books GET, HEAD /books Web::Controllers::Books::Index
- new_book GET, HEAD /books/new Web::Controllers::Books::New
- books POST /books Web::Controllers::Books::Create
-```
-
-The output shows you the name of the defined helper method (you can suffix this name with `_path` or `_url` and call it on the `routes` helper), the allowed HTTP method, the path and finally the controller action that will be used to handle the request.
-
-Now we've applied the `resources` helper method, we can take advantage of the named route methods.
-Remember how we built our form using `form_for` in `apps/web/templates/books/new.html.erb`?
-
-```erb
-<%=
- form_for :book, '/books' do
- # ...
- end
-%>
-```
-
-We don't need to include a hard-coded path in our template, when our router is already perfectly aware of which route to point the form to.
-We can use the `routes` helper method that is available in our views and actions to access route-specific helper methods:
-
-```erb
-<%=
- form_for :book, routes.books_path do
- # ...
- end
-%>
-```
-
-We can make a similar change in `apps/web/controllers/books/create.rb`:
-
-```ruby
-redirect_to routes.books_path
-```
-
-## Wrapping Up
-
-**Congratulations for completing your first Hanami project!**
-
-Let's review what we've done: we've traced requests through Hanami's major frameworks to understand how they relate to each other; we've seen how we can model our domain using entities and repositories; we've seen solutions for building forms, maintaining our database schema, and validating user input.
-
-We've come a long way, but there's still plenty more to explore.
-Explore the [other guides](/guides/1.1), the [Hanami API documentation](http://www.rubydoc.info/gems/hanami), read the [source code](https://github.com/hanami) and follow the [blog](/blog).
-
-**Above all, enjoy building amazing things!**
-
-
-
-
- Join a community of over 2,300+ developers.
-
-
-
- By clicking "Subscribe" I want to subscribe to Hanami mailing list.
-
-
-
diff --git a/source/guides/1.1/guides.yml b/source/guides/1.1/guides.yml
deleted file mode 100644
index db1d19eed..000000000
--- a/source/guides/1.1/guides.yml
+++ /dev/null
@@ -1,150 +0,0 @@
-categories:
- - path: /
- title: Introduction
- pages:
- - path: getting-started
- - path: architecture
- pages:
- - path: overview
- - path: interactors
- - path: projects
- pages:
- - path: code-reloading
- - path: rake
- - path: logging
- - path: initializers
- - path: security
- - path: routing
- pages:
- - path: overview
- - path: basic-usage
- - path: restful-resources
- title: RESTful Resource(s)
- - path: testing
- - path: actions
- pages:
- - path: overview
- - path: basic-usage
- - path: parameters
- - path: request-and-response
- title: Request & Response
- - path: exposures
- - path: rack-integration
- - path: mime-types
- title: MIME Types
- - path: cookies
- - path: sessions
- - path: exception-handling
- - path: control-flow
- - path: http-caching
- title: HTTP Caching
- - path: share-code
- - path: testing
- - path: views
- pages:
- - path: overview
- - path: basic-usage
- - path: templates
- - path: mime-types
- title: MIME Types
- - path: layouts
- - path: custom-error-pages
- - path: share-code
- - path: testing
- - path: models
- pages:
- - path: overview
- - path: database-configuration
- - path: use-your-own-orm
- title: Use Your Own ORM
- - path: repositories
- pages:
- - path: overview
- - path: sql-queries
- title: SQL Queries
- - path: postgresql
- title: PostgreSQL
- - path: entities
- pages:
- - path: overview
- - path: custom-schema
- - path: data-types
- - path: associations
- pages:
- - path: overview
- - path: has-many
- - path: belongs-to
- - path: has-one
- - path: has-many-through
- - path: migrations
- pages:
- - path: overview
- - path: create-table
- - path: alter-table
- - path: validations
- pages:
- - path: overview
- - path: boolean-logic
- - path: custom-predicates
- - path: advanced-usage
- - path: helpers
- pages:
- - path: overview
- - path: html5
- title: HTML5
- - path: forms
- - path: routing
- - path: assets
- - path: links
- - path: escape
- title: Markup Escape
- - path: numbers
- - path: custom-helpers
- - path: mailers
- pages:
- - path: overview
- - path: basic-usage
- - path: templates
- - path: delivery
- - path: share-code
- - path: testing
- - path: assets
- pages:
- - path: overview
- - path: preprocessors
- - path: compressors
- - path: content-delivery-network
- title: Content Delivery Network (CDN)
- - path: use-your-own-assets-management-tool
- title: Use Your Own Assets Management Tool
- - path: command-line
- pages:
- - path: applications
- - path: generators
- - path: destroy
- - path: database
- - path: assets
- - path: routes
- - path: version
- - path: plugins
- - path: upgrade-notes
- pages:
- - path: v060
- title: v0.6.0
- - path: v070
- title: v0.7.0
- - path: v080
- title: v0.8.0
- - path: v090
- title: v0.9.0
- - path: v100
- title: v1.0.0
- - path: v110
- title: v1.1.0
- - path: /
- title: Guide Versions
- pages:
- - path: ''
- title: 'v1.1'
- - path: '1.0'
- title: v1.0
diff --git a/source/guides/1.1/helpers/assets.md b/source/guides/1.1/helpers/assets.md
deleted file mode 100644
index 12bf15b26..000000000
--- a/source/guides/1.1/helpers/assets.md
+++ /dev/null
@@ -1,419 +0,0 @@
----
-title: Guides - Assets Helpers
-version: 1.1
----
-
-## Assets Helpers
-
-These helpers are HTML5 generators that target specific assets features.
-
-They are following the settings of the application that uses them.
-For instance, if we have a project with two applications `Web` and `Admin` mounted at `/` and `/admin`, respectively, all the asset URLs will respect these prefixes.
-
-They also respect [_Fingerprint mode_](/guides/1.1/assets/overview#fingerprint-mode) and [_CDN mode_](/guides/1.1/assets/content-delivery-network) for each application.
-
-The following helpers are available for views and templates:
-
- * `javascript`
- * `stylesheet`
- * `favicon`
- * `image`
- * `video`
- * `audio`
- * `asset_path`
- * `asset_url`
-
-## Usage
-
-### `javascript`
-
-It generates a `
-
-```
-
-Alternatively, it accepts **only one** source and a Hash to represent HTML attributes.
-
-```erb
-<%= javascript 'application', async: true %>
-```
-
-```html
-
-```
-
-### `stylesheet`
-
-It generates a `
` tag for the given source(s).
-A source can be the file name without the extension, or an absolute URL.
-
-```erb
-<%= stylesheet 'reset', 'grid', 'main' %>
-```
-
-```html
-
-
-
-```
-
-Alternatively, it accepts **only one** source and a Hash to represent HTML attributes.
-
-```erb
-<%= stylesheet 'application', crossorigin: 'anonymous' %>
-```
-
-```html
-
-```
-
-### `favicon`
-
-It generates a `
` tag for the application favicon.
-
-By default it looks at `/assets/favicon.ico`.
-
-```erb
-<%= favicon %>
-```
-
-```html
-
-```
-
-We can specify a source name and HTML attributes.
-
-```erb
-<%= favicon 'favicon.png', rel: 'icon', type: 'image/png' %>
-```
-
-```html
-
-```
-
-### `image`
-
-It generates a `
` tag for the given source.
-A source can be the file name with the extension, or an absolute URL.
-
-The `alt` attribute is set automatically from file name.
-
-```erb
-<%= image 'logo.png' %>
-```
-
-```html
-
-```
-
-We can specify arbitrary HTML attributes.
-
-```erb
-<%= image 'logo.png', alt: 'Application Logo', id: 'logo', class: 'background' %>
-```
-
-```html
-
-```
-
-### `video`
-
-It generates a `
` tag for the given source.
-A source can be the file name with the extension, or an absolute URL.
-
-```erb
-<%= video 'movie.mp4' %>
-```
-
-```html
-
-```
-
-We can specify arbitrary HTML attributes.
-
-```erb
-<%= video 'movie.mp4', autoplay: true, controls: true %>
-```
-
-```html
-
-```
-
-It accepts a block for fallback message.
-
-```erb
-<%=
- video('movie.mp4') do
- "Your browser does not support the video tag"
- end
-%>
-```
-
-```html
-
- Your browser does not support the video tag
-
-```
-
-It accepts a block to specify tracks.
-
-```erb
-<%=
- video('movie.mp4') do
- track kind: 'captions', src: asset_path('movie.en.vtt'), srclang: 'en', label: 'English'
- end
-%>
-```
-
-```html
-
-
-
-```
-
-It accepts a block to specify multiple sources.
-
-```erb
-<%=
- video do
- text "Your browser does not support the video tag"
- source src: asset_path('movie.mp4'), type: 'video/mp4'
- source src: asset_path('movie.ogg'), type: 'video/ogg'
- end
-%>
-```
-
-```html
-
- Your browser does not support the video tag
-
-
-
-```
-
-### `audio`
-
-It generates a `` tag for the given source.
-A source can be the file name with the extension, or an absolute URL.
-
-```erb
-<%= audio 'song.ogg' %>
-```
-
-```html
-
-```
-
-We can specify arbitrary HTML attributes.
-
-```erb
-<%= audio 'song.ogg', autoplay: true, controls: true %>
-```
-
-```html
-
-```
-
-It accepts a block for fallback message.
-
-```erb
-<%=
- audio('song.ogg') do
- "Your browser does not support the audio tag"
- end
-%>
-```
-
-```html
-
- Your browser does not support the audio tag
-
-```
-
-It accepts a block to specify tracks.
-
-```erb
-<%=
- audio('song.ogg') do
- track kind: 'captions', src: asset_path('movie.en.vtt'), srclang: 'en', label: 'English'
- end
-%>
-```
-
-```html
-
-
-
-```
-
-It accepts a block to specify multiple sources.
-
-```erb
-<%=
- audio do
- text "Your browser does not support the audio tag"
- source src: asset_path('song.ogg'), type: 'audio/mp4'
- source src: asset_path('movie.ogg'), type: 'audio/ogg'
- end
-%>
-```
-
-```html
-
- Your browser does not support the audio tag
-
-
-
-```
-
-### `asset_path`
-
-Returns a **relative URL** for the given asset name.
-
-**This is used internally by the other helpers, so the following rules apply to all of them.**
-
-#### Asset Name
-
-When the argument is a relative name, it returns a relative URL.
-
-```erb
-<%= asset_path 'application.js' %>
-```
-
-```html
-/assets/application.js
-```
-
-#### Absolute URL
-
-When an absolute URL is given, it's **always** returned as it is, even if _Fingerprint_ or _CDN_ mode are on.
-
-```erb
-<%= asset_path 'https://code.jquery.com/jquery-2.1.1.min.js' %>
-```
-
-```html
-https://code.jquery.com/jquery-2.1.1.min.js
-```
-
-#### Fingerprint Mode
-
-When [_Fingerprint Mode_](/guides/1.1/assets/overview#fingerprint-mode) is on (usually in _production_ env), the relative URL contains a checksum suffix.
-
-```erb
-<%= asset_path 'application.css' %>
-```
-
-```html
-/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-#### CDN Mode
-
-When [_CDN Mode_](/guides/1.1/assets/content-delivery-network) is on (usually in _production_ env), it returns an absolute URL that reference the CDN settings.
-
-```erb
-<%= asset_path 'application.css' %>
-```
-
-```html
-https://123.cloudfront.net/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-
- In the example above we have a checksum suffix, because CDN vendors suggest to use this strategy while using their product.
-
-
-### `asset_url`
-
-Returns an **absolute URL** for the given asset name.
-
-To build the URL it uses `scheme`, `host`, `port` from your application settings in combination of CDN settings.
-
-#### Asset Name
-
-When the argument is a relative name, it returns an absolute URL.
-
-```erb
-<%= asset_url 'application.js' %>
-```
-
-```html
-https://bookshelf.org/assets/application.js
-```
-
-#### Absolute URL
-
-When an absolute URL is given, it's **always** returned as it is, even if _Fingerprint_ or _CDN_ mode are on.
-
-```erb
-<%= asset_url 'https://code.jquery.com/jquery-2.1.1.min.js' %>
-```
-
-```html
-https://code.jquery.com/jquery-2.1.1.min.js
-```
-
-#### Fingerprint Mode
-
-When [_Fingerprint Mode_](/guides/1.1/assets/overview#fingerprint-mode) is on (usually in _production_ env), the relative URL contains a checksum suffix.
-
-```erb
-<%= asset_url 'application.css' %>
-```
-
-```html
-https://bookshelf.org/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-#### CDN Mode
-
-When [_CDN Mode_](/guides/1.1/assets/content-delivery-network) is on (usually in _production_ env), it returns an absolute URL that reference the CDN settings.
-
-```erb
-<%= asset_url 'application.css' %>
-```
-
-```html
-https://123.cloudfront.net/assets/application-9ab4d1f57027f0d40738ab8ab70aba86.css
-```
-
-
- In the example above we have a checksum suffix, because CDN vendors suggest to use this strategy while using their product.
-
-
-
-## Content Security Policy
-
-When using **absolute URLs as sources** or when we use a CDN, we can run into errors because our browser refute to load assets due to security restrictions (aka _"Content Security Policy"_).
-
-To fix them, we need to adjust security settings in our application.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- # If we're using our own CDN
- security.content_security_policy "default-src https://123.cloudfront.net;"
-
- # Or if we're just using jQuery public CDN
- # security.content_security_policy "default-src none; script-src 'self' https://code.jquery.com;"
- end
- end
-end
-```
-
-To learn more about Content Security Policy usage, please read:
-
- * [http://content-security-policy.com](http://content-security-policy.com)
- * [https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_Content_Security_Policy](https://developer.mozilla.org/en-US/docs/Web/Security/CSP/Using_Content_Security_Policy)
diff --git a/source/guides/1.1/helpers/custom-helpers.md b/source/guides/1.1/helpers/custom-helpers.md
deleted file mode 100644
index c9fb72423..000000000
--- a/source/guides/1.1/helpers/custom-helpers.md
+++ /dev/null
@@ -1,70 +0,0 @@
----
-title: Guides - Custom Helpers
-version: 1.1
----
-
-## Custom Helpers
-
-In the [overview](/guides/1.1/helpers/overview) section, we introduced the design for helpers.
-They are modules that enrich views behaviors.
-Because they are just Ruby modules, **we can create our own helpers**.
-
-### Example
-
-Imagine we need (for some reason) a helper that shuffles the characters of a string and we want it to be available in our views.
-
-As first thing, let's define the module.
-
-```ruby
-# app/web/helpers/shuffler.rb
-module Web
- module Helpers
- module Shuffler
- private
- SEPARATOR = ''.freeze
-
- def shuffle(string)
- string
- .encode(Encoding::UTF_8, invalid: :replace)
- .split(SEPARATOR).shuffle.join
- end
- end
- end
-end
-```
-
-
- There is NO convention between the file name and the name of the module.
- We can define this code, where and how we want.
-
-
-Then let's add that directory to the load paths of the application, so it can be eagerly loaded.
-As third step, we include the module in all the views. See [View's Share Code](/guides/1.1/views/share-code) section for low level details.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- load_paths << [
- 'helpers',
- 'controllers',
- 'views'
- ]
-
- # ...
-
- view.prepare do
- include Hanami::Helpers
- include Web::Helpers::Shuffler
- end
- end
- end
-end
-```
-
-
- Please note that our custom helper will work even if we remove include Hanami::Helpers
line, because it's just Ruby.
-
diff --git a/source/guides/1.1/helpers/escape.md b/source/guides/1.1/helpers/escape.md
deleted file mode 100644
index 209fbcb07..000000000
--- a/source/guides/1.1/helpers/escape.md
+++ /dev/null
@@ -1,139 +0,0 @@
----
-title: Guides - Markup Escape Helpers
-version: 1.1
----
-
-## Markup Escape Helpers
-
-**Views escape automatically the output of their methods.**
-There are complex situations that views can't cover properly and that require an extra attention from us.
-
-Hanami makes available a set of escape helpers, to increase the security of our web applications.
-They are **public methods** that are available both in views and templates.
-
-## Escape HTML Contents
-
-It's a method called `#escape_html` (aliased as `#h`), that escapes the input.
-
-```erb
-<%= h "" %>
-```
-
-Returns
-
-```html
-<script>alert('xss')</script>
-```
-
-## Escape HTML Attributes
-
-HTML attributes are more complex to escape, because they involve attribute delimitation chars (eg. single or double quotes).
-
-We have an extra helper for this specific task: `#escape_html_attribute` (aliased as `#ha`)
-**This should be used only when the value of an attribute comes from a user input.**
-
-```erb
-
-```
-
-## Whitelisted URLs
-
-Imagine we have a feature in our application that allows users to link from their profile, a website.
-In the edit profile form we have a text field that accepts a URL.
-
-In the profile page we have a link like this:
-
-```erb
-<%= link_to "Website", user.website_url %>
-```
-
-A malicious user can edit their profile, by entering javascript code as the website URL.
-When somebody else clicks on that link, they can receive an XSS attack.
-
-Example:
-
-```html
-Website
-```
-
-The solution to this problem is to wrap the output with the `#escape_url` (aliased as `#hu`) helper.
-
-It whitelists URLs that use `http`, `https`, and `mailto` schemes, everything else is scraped.
-
-```erb
-<%= link_to "Website", hu(user.website_url) %>
-```
-
-In case we need a different set of schemes, we can specify them as second argument.
-
-```erb
-<%= link_to "Website", hu(user.website_url, ['https']) %>
-```
-
-In the code above, we're restricting to URLs that only use HTTPS.
-
-## Raw Contents
-
-There are cases when we want to print the raw contents.
-**Please be careful with this, because unescaped contents can open a breach for XSS attacks.**
-
-The helper is called `#raw`.
-
-### Specific Local
-
-If we want to escape a specific _local_:
-
-```ruby
-# apps/web/controllers/snippets/show.rb
-
-module Web::Controllers::Snippets
- class Show
- include Web::Action
-
- expose :snippet
-
- def call(params)
- @snippet = "Hello World "
- end
- end
-end
-```
-
-```ruby
-# apps/web/views/snippets/show.rb
-
-module Web::Views::Snippets
- class Show
- include Web::View
-
- def snippet
- raw locals[:snippet]
- end
- end
-end
-```
-
-```erb
-# apps/web/views/snippets/show.html.erb
-
-<%= snippet %>
-```
-
-### Entire Output
-
-We can also return unescaped output for the entire view:
-
-```ruby
-# apps/web/views/books/json_show.rb
-require 'json'
-
-module Web::Views::Books
- class JsonShow < Show
- format :json
-
- def render
- raw JSON.generate(book.to_h)
- end
- end
-end
-```
diff --git a/source/guides/1.1/helpers/forms.md b/source/guides/1.1/helpers/forms.md
deleted file mode 100644
index dee8876ca..000000000
--- a/source/guides/1.1/helpers/forms.md
+++ /dev/null
@@ -1,309 +0,0 @@
----
-title: Guides - Form Helpers
-version: 1.1
----
-
-## Form Helpers
-
-It provides a powerful Ruby API to describe HTML5 forms, to be used both with views and templates. It ships with:
-
- * Support for complex markup without the need of concatenation
- * Auto closing HTML5 tags
- * Support for view local variables
- * Method override support (`PUT`/`PATCH`/`DELETE` HTTP verbs aren't understood by browsers)
- * Automatic generation of HTML attributes for inputs: `id`, `name`, `value`
- * Allow to override automatic HTML attributes
- * Read values from request params and/or given entities, to autofill `value` attributes
- * Automatic selection of current value for radio button and select inputs
- * CSRF Protection
- * Infinite nested fields
- * ORM Agnostic
-
-## Technical notes
-
-This feature has a similar syntax to other Ruby gems with the same purpose, but it has a different usage if compared with Rails or Padrino.
-
-Those frameworks allow a syntax like this:
-
-```erb
-<%= form_for :book do |f| %>
-
- <%= f.text_field :title %>
-
-<% end %>
-```
-
-The code above **isn't a valid ERB template**.
-To make it work, these frameworks use custom ERB handlers and rely on third-party gems for other template engines.
-
-### Template engine independent
-
-Because we support a lot of template engines, we wanted to keep it simple: use what ERB already offers.
-That means we can use Slim, HAML, or ERB and keep the same Ruby syntax.
-
-### One output block
-
-The technical compromise for the principles described above is to use the form builder in a unique output block.
-
-```erb
-<%=
- form_for :book, routes.books_path do
- text_field :title
-
- submit 'Create'
- end
-%>
-```
-
-This will produce
-
-```html
-
-```
-
-### Method in views
-
-An **alternative usage** is to define a concrete method in a view and to use it in the template:
-
-```ruby
-module Web::Views::Books
- class New
- include Web::View
-
- def form
- form_for :book, routes.books_path do
- text_field :title
-
- submit 'Create'
- end
- end
- end
-end
-```
-
-```erb
-<%= form %>
-```
-
-### Supported methods
-
-* [check_box](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#check_box-instance_method)
-* [color_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#color_field-instance_method)
-* [datalist](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#datalist-instance_method)
-* [date_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#date_field-instance_method)
-* [datetime_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#datetime_field-instance_method)
-* [datetime\_local_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#datetime_local_field-instance_method)
-* [email_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#email_field-instance_method)
-* [fields_for](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#fields_for-instance_method)
-* [fields\_for_collection](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder:fields_for_collection)
-* [file_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#file_field-instance_method)
-* [form_for](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper#form_for-instance_method)
-* [hidden_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#hidden_field-instance_method)
-* [label](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#label-instance_method)
-* [number_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#number_field-instance_method)
-* [password_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#password_field-instance_method)
-* [radio_button](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#radio_button-instance_method)
-* [select](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#select-instance_method)
-* [submit](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#submit-instance_method)
-* [text_area](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#text_area-instance_method)
-* [text_field](http://www.rubydoc.info/gems/hanami-helpers/Hanami/Helpers/FormHelper/FormBuilder#text_field-instance_method)
-
-## Examples
-
-### Basic usage
-
-The API is really clean and concise, **it doesn't require concatenation** between the returning value of the block (`submit`) and the previous lines (`div`).
-
-```erb
-<%=
- form_for :book, routes.books_path, class: 'form-horizontal' do
- div do
- label :title
- text_field :title, class: 'form-control'
- end
-
- submit 'Create'
- end
-%>
-```
-
-```html
-
-```
-
-### Method override
-
-Browsers don't understand HTTP methods outside of `GET` and `POST`. On the other hand, Hanami embraces REST conventions, that goes beyond that two verbs. When we specify a method via `:method`, it adds a special hidden field `_method`, that's understood by the application.
-
-```erb
-<%=
- form_for :book, routes.book_path(book.id), method: :put do
- text_field :title
-
- submit 'Update'
- end
-%>
-```
-
-```html
-
-```
-
-### CSRF Protection
-
-Cross Site Request Forgery (CSRF) is one of the most common attacks on the web. Hanami offers a security mechanism based on a technique called: _Synchronizer Token Pattern_.
-
-When we enable sessions, it uses them to store a random token for each user.
-Forms are rendered with a special hidden field (`_csrf_token`) which contains this token.
-
-On form submission, Hanami matches this input with the value from the session. If they match, the request can continue. If not, it resets the session and raises an exception.
-
-Developers can customize attack handling.
-
-### Nested fields
-
-```erb
-<%=
- form_for :delivery, routes.deliveries_path do
- text_field :customer_name
-
- fields_for :address do
- text_field :city
- end
-
- submit 'Create'
- end
-%>
-```
-
-```html
-
-```
-
-### Nested collections
-```erb
-<%=
- form_for :delivery, routes.deliveries_path do
- text_field :customer_name
-
- fields_for_collection :addresses do
- text_field :street
- end
-
- submit 'Create'
-end
-%>
-```
-
-```html
-
-```
-
-## Automatic values
-
-Form fields are **automatically filled with the right value**. Hanami looks up for explicit values passed in the form constructor and for the params of the current request. It compares the form hierarchy (including nested fields), with these two sources. For each match, it fills the associated value.
-
-#### Example
-
-Imagine we want to update data for `delivery`. We have two objects: `delivery` and `customer`, which are plain objects (no ORM involved). They respond to the following methods:
-
-```ruby
-delivery.id # => 1
-delivery.code # => 123
-
-customer.name # => "Luca"
-
-customer.address.class # => Address
-customer.address.city # => "Rome"
-```
-
-Let's compose the form.
-
-```erb
-<%=
- form_for :delivery, routes.delivery_path(id: delivery.id), method: :patch, values: {delivery: delivery, customer: customer} do
- text_field :code
-
- fields_for :customer do
- text_field :name
-
- fields_for :address do
- text_field :city
- end
- end
-
- submit 'Update'
- end
-%>
-```
-
-```html
-
-```
-
-Please note the `:values` option that we pass to `#form_for`. It maps the `name` attributes that we have in the form with the objects that we want to use to fill the values. For instance `delivery[code]` corresponds to `delivery.code` (`123`), `delivery[customer][address][city]` to `customer.address.city` (`"Rome"`) and so on..
-
-### Read Values From Params
-
-**Params are automatically passed to form helpers**, to read values and try to autofill fields. If a value is present both in params and explicit values (`:values`), the first takes precendence. The reason is simple: params sometimes represent a failed form submission attempt.
-
-#### Example
-
-Imagine the form described above, and that our user enters `"foo"` as delivery code. This value isn't acceptable for our model domain rules, so we render again the form, presenting a validation error. Our params are now carrying on the values filled by our user. For instance: `params.get('delivery.code')` returns `"foo"`.
-
-Here how the form is rendered:
-
-```html
-
-```
diff --git a/source/guides/1.1/helpers/html5.md b/source/guides/1.1/helpers/html5.md
deleted file mode 100644
index 0eb4d7f74..000000000
--- a/source/guides/1.1/helpers/html5.md
+++ /dev/null
@@ -1,221 +0,0 @@
----
-title: Guides - HTML5 Helpers
-version: 1.1
----
-
-## HTML5 Helpers
-
-This helper makes available an HTML5 generator that is **template engine independent**.
-It's a **private method for views and layouts** called `#html`.
-
-## Usage
-
-This is how it will look used with a layout:
-
-```ruby
-module Web::Views
- class ApplicationLayout
- include Web::Layout
-
- def sidebar
- html.aside(id: 'sidebar') do
- div 'hello'
- end
- end
- end
-end
-```
-
-```erb
-<%= sidebar %>
-```
-
-It generates:
-
-```html
-
-```
-
-## Features
-
- * It knows how to close tags according to HTML5 spec (1)
- * It accepts content as first argument (2)
- * It accepts builder as first argument (3)
- * It accepts content as block which returns a string (4)
- * It accepts content as a block with nested markup builders (5)
- * It builds attributes from given hash (6)
- * it combines attributes and block (7)
-
-```ruby
-# 1
-html.div # =>
-html.img # =>
-
-# 2
-html.div('hello') # => hello
-
-# 3
-html.div(html.p('hello')) # =>
-
-# 4
-html.div { 'hello' }
-# =>
-#
-# hello
-#
-
-# 5
-html.div do
- p 'hello'
-end
-# =>
-#
-
-# 6
-html.div('hello', id: 'el', 'data-x': 'y') # => hello
-
-# 7
-html.div(id: 'yay') { 'hello' }
-# =>
-#
-# hello
-#
-```
-
-It supports complex markup constructs, **without the need of concatenate tags**. In the following example, there are two `div` tags that we don't need link together.
-
-```ruby
-html.section(id: 'container') do
- div(id: 'main') do
- p 'Main content'
- end
-
- div do
- ul(id: 'languages') do
- li 'Italian'
- li 'English'
- end
- end
-end
-
-# =>
-#
-```
-
-The result is a very clean Ruby API.
-
-## Custom tags
-
-Hanami helpers support 100+ most common tags, such as `div`, `video` or `canvas`.
-However, HTML5 is fast moving target so we wanted to provide an open interface to define **new or custom tags**.
-
-The API is really simple: `#tag` must be used for a self-closing tag, where `#empty_tag` does the opposite.
-
-```ruby
-html.tag(:custom, 'Foo', id: 'next') # => Foo
-html.empty_tag(:xr, id: 'next') # =>
-```
-
-## Other helpers
-
-Hanami html helpers also support other assembled helpers. For example `link_to` helper:
-
-```ruby
-html.div do
- link_to 'hello', routes.root_path, class: 'btn'
-end
-# =>
-
-html.div do
- link_to 'Users', routes.users_path, class: 'btn'
- hr
- link_to 'Books', routes.books_path, class: 'btn'
-end
-
-# =>
-```
-
-## Auto escape
-
-The tag contents are automatically escaped for **security** reasons:
-
-```ruby
-html.div('hello') # => hello
-html.div { 'hello' } # => hello
-html.div(html.p('hello')) # =>
-html.div do
- p 'hello'
-end # =>
-
-
-
-html.div("")
- # => "<script>alert('xss')</script>
"
-
-html.div { "" }
- # => "<script>alert('xss')</script>
"
-
-html.div(html.p(""))
- # => "<script>alert('xss')</script>
"
-
-html.div do
- p ""
-end
- # => "<script>alert('xss')</script>
"
-```
-
-**HTML attributes aren't automatically escaped**, in case we need to use a value that comes from a user input, we suggest to use `#ha`, which is the escape helper designed for this case. See [Escape Helpers](/guides/1.1/helpers/escape) for a deep explanation.
-
-## View Context
-
-Local variables from views are available inside the nested blocks of HTML builder:
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def title_widget
- html.div do
- h1 book.title
- end
- end
- end
-end
-```
-
-```erb
-
- <%= title_widget %>
-
-```
-
-```html
-
-
-
The Work of Art in the Age of Mechanical Reproduction
-
-
-```
-
diff --git a/source/guides/1.1/helpers/links.md b/source/guides/1.1/helpers/links.md
deleted file mode 100644
index cd1a660cb..000000000
--- a/source/guides/1.1/helpers/links.md
+++ /dev/null
@@ -1,71 +0,0 @@
----
-title: Guides - Link Helpers
-version: 1.1
----
-
-## Link Helpers
-
-It provides a concise API to generate links.
-It's a **public method** called `#link_to`, that can be used both in **views** and **templates**.
-
-## Usage
-
-It accepts two mandatory and one optional arguments.
-The first is the content of the tag, the second is the path, an the third is a Hash that represents a set of HTML attributes that we may want to specify.
-
-```erb
-<%= link_to 'Home', '/' %>
-<%= link_to 'Profile', routes.profile_path, class: 'btn', title: 'Your profile' %>
-<%=
- link_to(routes.profile_path, class: 'avatar', title: 'Your profile') do
- img(src: user.avatar.url)
- end
-%>
-```
-
-Output:
-
-```html
-Home
-Profile
-
-
-
-```
-
-Alternatively, the content can be expressed as a given block.
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def look_inside_link
- url = routes.look_inside_book_path(id: book.id)
-
- link_to url, class: 'book-cover' do
- html.img(src: book.cover_url)
- end
- end
- end
-end
-```
-
-Template:
-
-```erb
-<%= look_inside_link %>
-```
-
-Output:
-
-```html
-
-
-
-```
-
-## Security
-
-There are two aspects to consider when we use links in our markup: **whitelisted URLs** and **escaped attributes**.
-Please visit the [Markup Escape](/guides/1.1/helpers/escape) section for a detailed explanation.
diff --git a/source/guides/1.1/helpers/numbers.md b/source/guides/1.1/helpers/numbers.md
deleted file mode 100644
index 3bae7d3d9..000000000
--- a/source/guides/1.1/helpers/numbers.md
+++ /dev/null
@@ -1,57 +0,0 @@
----
-title: Guides - Number Helpers
-version: 1.1
----
-
-## Number Helpers
-
-Hanami offers a helpful way to present numbers via `#format_number`, a **private method** available only in views.
-
-## Usage
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def download_count
- format_number book.download_count
- end
- end
-end
-```
-
-```erb
-<%= download_count %>
-```
-
-```html
-1,000,000
-```
-
-### Precision
-
-The default precision is of `2`, but we can specify a different value with the homonym option.
-
-```ruby
-format_number(Math::PI) # => "3.14"
-format_number(Math::PI, precision: 6) # => "3.141592"
-```
-
-### Delimiter
-
-The default thousands delimiter is `,`. We can use `:delimiter` for a different char.
-
-```ruby
-format_number(1_000_000) # => "1,000,000"
-format_number(1_000_000, delimiter: '.') # => "1.000.000"
-```
-
-### Separator
-
-The default separator is `.`. We can use `:separator` for a different char.
-
-```ruby
-format_number(1.23) # => "1.23"
-format_number(1.23, separator: ',') # => "1,23"
-```
diff --git a/source/guides/1.1/helpers/overview.md b/source/guides/1.1/helpers/overview.md
deleted file mode 100644
index 30de44d1e..000000000
--- a/source/guides/1.1/helpers/overview.md
+++ /dev/null
@@ -1,133 +0,0 @@
----
-title: Guides - Helpers Overview
-version: 1.1
----
-
-# Overview
-
-A Hanami view is an object that defines presentational logic.
-Helpers are modules designed to enrich views with a collection of useful features.
-
-This concept is probably familiar, if you know some Ruby basics.
-
-```ruby
-module Printable
- def print
- puts "..."
- end
-end
-
-class Person
- include Printable
-end
-
-Person.new.print
-```
-
-The same simple design is applied to views and helpers.
-
-Hanami ships with default helpers, but we can also define custom helper modules.
-
-## Rendering Context
-
-Views are Ruby objects that are responsible for rendering the associated template.
-The context for this activity is defined only by the set of methods that a view can respond to.
-
-If a view has a method `#greeting`, we can use it like this: `<%= greeting %>`.
-
-This design has a few important advantages:
-
- * It facilitates debugging. In the case of an exception, we know that **the view is the only rendering context to inspect**.
- * Ruby method dispatcher will be **fast**, as it doesn't need to do a lookup for many method sources.
-
-Consider the following code:
-
-```ruby
-# apps/web/views/books/show.rb
-module Web::Views::Books
- include Web::View
-
- def home_page_link
- link_to "Home", "/"
- end
-end
-```
-
-Our view responds to `#link_to`, because it includes `Hanami::Helpers::LinkToHelper`, a module that defines that concrete method.
-
-## Clean Context
-
-There are some helpers that have a huge interface.
-Think of the [HTML5](/guides/1.1/helpers/html5) or the [routing](/guides/1.1/helpers/routing) helpers, they provide hundreds of methods to map tags or application routes.
-
-Making them available directly in the view context, would be source of confusion, slow method dispatch times and name collisions.
-
-Imagine we have an application with 100 routes.
-Because Hanami provides both relative and absolute URI facilities, if used directly, it would mean adding **200 methods** to all the views.
-Which is overkill.
-
-For this reason, certain helpers act as a proxy to access these large set of methods.
-
-```erb
-<%= routes.home_path %>
-```
-
-In this case we have **only one method** to add to our views, but it opens an infinite number of possibilities without causing performance issues.
-
-## Explicit Interfaces
-
-Hanami guides developers to design explicit and intention revealing interfaces for their objects.
-Almost all the default helpers, make **private methods** available to our views.
-
-We want to avoid complex expressions that will clutter our templates, and make sure that views remain testable.
-
-Here an example of **poor** and **untestable** code in a template.
-
-```erb
-<%= format_number book.downloads_count %>
-```
-
-If we want to unit test this logic, we can't do it directly, unless we render the template and match the output.
-
-For this reason `#format_number`, is shipped as a private method, so we are forced to define an explicit method for our interface.
-
-```ruby
-# apps/web/views/books/show.rb
-module Web::Views::Books
- include Web::View
-
- def downloads_count
- format_number book.downloads_count
- end
-end
-```
-
-To be used like this:
-
-```erb
-<%= downloads_count %>
-```
-
-This version is **visually simpler** and **testable**.
-
-## Disable Helpers
-
-Helpers aren't mandatory for Hanami applications.
-If we want to get rid of them, we just to need to remove two lines of code.
-
-```ruby
-# apps/web/application.rb
-require 'hanami/helpers' # REMOVE THIS LINE
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
-
- view.prepare do
- include Hanami::Helpers # AND THIS ONE
- end
- end
- end
-end
-```
diff --git a/source/guides/1.1/helpers/routing.md b/source/guides/1.1/helpers/routing.md
deleted file mode 100644
index 102d5d0e5..000000000
--- a/source/guides/1.1/helpers/routing.md
+++ /dev/null
@@ -1,68 +0,0 @@
----
-title: Guides - Routing Helpers
-version: 1.1
----
-
-## Routing Helpers
-
-Routing helpers are made of one **public method** (`#routes`), available for actions, views and templates.
-It's a factory to generate **relative** or **absolute URLs**, starting from [named routes](/guides/1.1/routing/basic-usage).
-
-
- For a given route named :home
, we can use home_path
or home_url
to generate relative or absolute URLs, respectively.
-
-
-## Usage
-
-Imagine we have the following routes for our application:
-
-```ruby
-# apps/web/config/routes.rb
-root to: 'home#index'
-get '/foo', to: 'foo#index'
-
-resources :books
-```
-
-### Relative URLs
-
-We can do:
-
-```erb
-
-```
-
-Which generates:
-
-```html
-
-```
-
-We can't link `/foo`, because it isn't a named route (it lacks of the `:as` option).
-
-### Absolute URLs
-
-```ruby
-module Web::Controllers::Books
- class Create
- include Web::Action
-
- def call(params)
- # ...
- redirect_to routes.book_url(id: book.id)
- end
- end
-end
-```
-
-In the case above, we have passed a Hash as set of params that are required to generate the URL.
-
-
- Absolute URL generation is dependent on scheme
, host
and port
settings in apps/web/application.rb
.
-
diff --git a/source/guides/1.1/index.md b/source/guides/1.1/index.md
deleted file mode 100644
index 0dea34670..000000000
--- a/source/guides/1.1/index.md
+++ /dev/null
@@ -1,48 +0,0 @@
----
-title: Guides
-version: 1.1
----
-
-# Introduction
-
-## What is Hanami?
-
-Hanami is a Ruby MVC web framework comprised of many micro-libraries.
-It has a simple, stable API, a minimal DSL, and prioritises the use of plain objects over magical, over-complicated classes with too much responsibility.
-
-The natural repercussion of using simple objects with clear responsibilities is more boilerplate code.
-Hanami provides ways to mitigate this extra legwork while maintaining the underlying implementation.
-
-## Why Choose Hanami?
-
-Here are three compelling reasons to choose Hanami:
-
-### Hanami is Lightweight
-
-Hanami's code is relatively short.
-It only concerns itself with the things that all web applications—regardless of implementation—need.
-
-Hanami ships with several optional modules and other libraries can also be included easily.
-
-### Hanami is Architecturally Sound
-
-If you've ever felt you're stretching against the "Rails way", you'll appreciate Hanami.
-
-Hanami keeps controller actions class-based, making them easier to test in isolation.
-
-Hanami also encourages you to write your application logic in use cases objects (aka _interactors_).
-
-Views are separated from templates so the logic inside can be well-contained and tested in isolation.
-
-### Hanami is Threadsafe
-
-Making use of threads is a great way to boost the performance of your
-application. It shouldn't be hard to write thread-safe code, and Hanami (whether
-the entire framework, or parts of it) is runtime threadsafe.
-
-## Guides
-
-The guides explain high level Hanami components and how to configure, use and test them in a full stack application.
-The imaginary product that we'll mention is called _"Bookshelf"_: a online community to share readings and buy books.
-
-We have a [getting started guide](/guides/1.1/getting-started), to build our first application with Hanami.
diff --git a/source/guides/1.1/mailers/basic-usage.md b/source/guides/1.1/mailers/basic-usage.md
deleted file mode 100644
index d220ed9e1..000000000
--- a/source/guides/1.1/mailers/basic-usage.md
+++ /dev/null
@@ -1,107 +0,0 @@
----
-title: Guides - Mailers Basic Usage
-version: 1.1
----
-
-# Basic Usage
-
-In the [previous section](/guides/1.1/mailers/overview), we generated a mailer, let's use it.
-
-## Information
-
-Firstly, we need to specify sender and recipient(s) and the subject of the email.
-For this purpose a mailer exposes three mandatory methods: `.from`, `.to`, `.subject` and two optional: `.cc`, `.bcc`.
-
-They all accept a string, but `.to` can also accept an array of strings in order to set multiple recipients.
-
-```ruby
-class Mailers::Welcome
- include Hanami::Mailer
-
- from 'noreply@bookshelf.org'
- to 'user@example.com'
- subject 'Welcome to Bookshelf'
-end
-```
-
-
- Both .from
and .to
MUST be specified when we deliver an email.
-
-
-
- An email subject isn't mandatory, but it's a good practice to set this information.
-
-
-You may have noticed that have a hardcoded value can be useful to set the sender, but it doesn't work well for the rest of the details.
-
-If you pass a **symbol as an argument**, it will be interpreted as a **method** that we want to use for that information.
-
-
-```ruby
-class Mailers::Welcome
- include Hanami::Mailer
-
- from 'noreply@bookshelf.org'
- to :recipient
- subject :subject
-
- private
-
- def recipient
- user.email
- end
-
- def subject
- "Welcome #{ user.name }!"
- end
-end
-```
-
-
- There is NOT a convention between the name of the methods and their corresponding DSL.
-
-
-
- We suggest to use always private methods for these informations, unless they need to be available from the templates.
-
-
-## Context
-
-### Locals
-
-In the previous section, we have referenced an `user` variable, where does it come from?
-Similarly to a [view](/guides/1.1/views/basic-usage), a mailer can have a set of _locals_ that can be passed as an argument in order to make them available during the rendering.
-
-```ruby
-u = User.new(name: 'Luca', email: 'luca@example.com')
-Mailers::Welcome.deliver(user: u)
-```
-
-We can specify as many locals as we want, the key that we use for each of them it's the same that we use to reference that object.
-For instance, we passed `:user` key, and we can use `user` in the mailer and its associated templates.
-
-
- The following keys for locals are RESERVED: :format
and :charset
.
-
-
-### Scope
-
-All the public methods defined in a mailer are accessible from the templates:
-
-```ruby
-# lib/bookshelf/mailers/welcome.rb
-class Mailers::Welcome
- include Hanami::Mailer
-
- # ...
-
- def greeting
- "Ahoy"
- end
-end
-```
-
-```erb
-# lib/bookshelf/mailers/templates/welcome.html.erb
-<%= greeting %>
-```
diff --git a/source/guides/1.1/mailers/delivery.md b/source/guides/1.1/mailers/delivery.md
deleted file mode 100644
index 7b357b93a..000000000
--- a/source/guides/1.1/mailers/delivery.md
+++ /dev/null
@@ -1,148 +0,0 @@
----
-title: Guides - Mailers Delivery
-version: 1.1
----
-
-# Delivery
-
-## Multipart Delivery
-
-By default a mailer delivers a multipart email, that has a HTML and a text part.
-This is the reason why the generator creates two templates.
-
-To render both the templates and deliver them as a multipart message, we simply do:
-
-```ruby
-Mailers::Welcome.deliver
-```
-
-Hanami mailers are flexible enough to adapt to several scenarios.
-
-## Single Part Delivery
-
-Let's say in our application users can opt for HTML or textual emails.
-According to this configuration, we want to selectively send only the wanted format:
-
-```ruby
-Mailers::Welcome.deliver(format: :html)
-# or
-Mailers::Welcome.deliver(format: :txt)
-```
-
-By using only one format, it will render and deliver only the specified template.
-
-## Remove Templates
-
-If in our application, we want only to deliver HTML templates, we can **safely** remove textual templates (`.txt` extension) and every time we will do `Mailers::Welcome.deliver` it will only send the HTML message.
-
-The same principle applies if we want only to send textual emails, just remove HTML templates (`.html` extension).
-
-
- At the delivery time, a mailer MUST have at least one template available.
-
-
-## Configuration
-
-In order to specify the gateway to use for our email messages, we can use `delivery` configuration.
-
-### Built-in Methods
-
-It accepts a symbol that is translated into a delivery strategy:
-
- * Exim (`:exim`)
- * Sendmail (`:sendmail`)
- * SMTP (`:smtp`, for local SMTP installations)
- * SMTP Connection (`:smtp_connection`, via `Net::SMTP` - for remote SMTP installations)
- * Test (`:test`, for testing purposes)
-
-It defaults to SMTP (`:smtp`) for production environment, while `:test` is automatically set for development and test.
-
-The second optional argument is a set of arbitrary configurations that we want to pass to the configuration:
-
-```ruby
-# config/environment.rb
-# ...
-Hanami.configure do
- # ...
-
- mailer do
- root Hanami.root.join("lib", "bookshelf", "mailers")
-
- # See http://hanamirb.org/guides/1.1/mailers/delivery
- delivery :test
- end
-
- # ...
-
- environment :production do
- # ...
-
- mailer do
- delivery :smtp, address: ENV['SMTP_HOST'], port: ENV['SMTP_PORT']
- end
- end
-end
-```
-
-For advanced configurations, please have a look at `mail` [gem](https://github.com/mikel/mail) by Mikel Lindsaar.
-At the low level, **Hanami::Mailer** uses this rock solid library.
-
-Because Hanami uses `mail` gem, which is a _de facto_ standard for Ruby, we can have interoperability with all the most common gateways vendors.
-[Sendgrid](https://devcenter.heroku.com/articles/sendgrid#ruby-rails), [Mandrill](https://devcenter.heroku.com/articles/mandrill#sending-with-smtp), [Postmark](https://devcenter.heroku.com/articles/postmark#sending-emails-via-the-postmark-smtp-interface) and [Mailgun](https://devcenter.heroku.com/articles/mailgun#sending-emails-via-smtp) just to name a few, use SMTP and have detailed setup guides.
-
-### Custom Methods
-
-If we need to a custom delivery workflow, we can pass a class to the configuration.
-
-Here's an example on how to use [Mandrill API](https://mandrillapp.com/api/docs/) to deliver emails.
-
-```ruby
-# config/environment.rb
-# ...
-require 'lib/mailers/mandrill_delivery_method'
-
-Hanami.configure do
- # ...
-
- environment :production do
- # ...
-
- mailer do
- production MandrillDeliveryMethod, api_key: ENV['MANDRILL_API_KEY']
- end
- end
-end
-```
-
-The object MUST respond to `#initialize(options = {})` and to `#deliver!(mail)`, where `mail` is an instance of [`Mail::Message`](https://github.com/mikel/mail/blob/master/lib/mail/mail.rb).
-
-```ruby
-class MandrillDeliveryMethod
- def initialize(options)
- @api_key = options.fetch(:api_key)
- end
-
- def deliver!(mail)
- send convert(mail)
- end
-
- private
-
- def send(message)
- gateway.messages.send message
- end
-
- def convert(mail)
- # Convert a Mail::Message instance into a Hash structure
- # See https://mandrillapp.com/api/docs/messages.ruby.html
- end
-
- def gateway
- Mandrill::API.new(@api_key)
- end
-end
-```
-
-
- Please notice that this is only an example that illustrates custom policies. If you want to use Mandrill, please prefer SMTP over this strategy.
-
diff --git a/source/guides/1.1/mailers/overview.md b/source/guides/1.1/mailers/overview.md
deleted file mode 100644
index d494785e8..000000000
--- a/source/guides/1.1/mailers/overview.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Guides - Mailers Overview
-version: 1.1
----
-
-# Overview
-
-A mailer is an object that's responsible to deliver a mail message, by rendering one or more templates.
-
-For simplicity, each mailer can handle **only one use case (feature)**.
-If in our application we need to send emails for several features like: _"confirm your email address"_ or _"forgot password"_, we will have `Mailers::ConfirmEmailAddress` and `Mailers::ForgotPassword` **instead** of a generic `UserMailer` that manages all these use cases.
-
-## A Simple Mailer
-
-Hanami ships a generator that creates a mailer, two templates and the test code.
-
-```shell
-% hanami generate mailer welcome
- create spec/bookshelf/mailers/welcome_spec.rb
- create lib/bookshelf/mailers/welcome.rb
- create lib/bookshelf/mailers/templates/welcome.html.erb
- create lib/bookshelf/mailers/templates/welcome.txt.erb
-```
-
-Let's see how a mailer is structured:
-
-```ruby
-# lib/bookshelf/mailers/welcome.rb
-class Mailers::Welcome
- include Hanami::Mailer
-end
-```
-
-
- All the mailers are available under the Mailers
namespace.
-
-
diff --git a/source/guides/1.1/mailers/share-code.md b/source/guides/1.1/mailers/share-code.md
deleted file mode 100644
index 75c4227ee..000000000
--- a/source/guides/1.1/mailers/share-code.md
+++ /dev/null
@@ -1,54 +0,0 @@
----
-title: Guides - Mailes Share Code
-version: 1.1
----
-
-# Share Code
-
-## Prepare
-
-In our settings (`lib/bookshelf.rb`), there is code block that allows to share the code for **all the mailers** of our application.
-When a mailer includes the `Hanami::Mailer` module, that block code is yielded within the context of that class.
-This is heavily inspired by Ruby Module and its `included` hook.
-
-Imagine we want to set a default sender for all the mailers.
-Instead of specifying it for each mailer, we can use a DRY approach.
-
-We create a module:
-
-```ruby
-# lib/mailers/default_sender.rb
-module Mailers::DefaultSender
- def self.included(mailer)
- mailer.class_eval do
- from 'sender@bookshelf.org'
- end
- end
-end
-```
-
-Then we include in all the mailers of our application, via `prepare`.
-
-```ruby
-# lib/bookshelf.rb
-# ...
-
-Hanami.configure do
- # ...
- mailer do
- root 'lib/bookshelf/mailers'
-
- # See http://hanamirb.org/guides/1.1/mailers/delivery
- delivery :test
-
- prepare do
- include Mailers::DefaultSender
- end
- end
-end
-```
-
-
-Code included via prepare
is available for ALL the mailers of an application.
-
-
diff --git a/source/guides/1.1/mailers/templates.md b/source/guides/1.1/mailers/templates.md
deleted file mode 100644
index 01a31ebd7..000000000
--- a/source/guides/1.1/mailers/templates.md
+++ /dev/null
@@ -1,191 +0,0 @@
----
-title: Guides - View Templates
-version: 1.1
----
-
-# Templates
-
-A template is a file that contains a body for a specific format of a multipart email.
-For instance, `welcome.html.erb` describes the markup of the HTML part of the message, while `welcome.txt.erb` is for the textual part.
-
-It is rendered by bounding the [context](/guides/1.1/mailers/basic-usage) of a mailer and using a _template engine_.
-
-## Naming
-
-For convenience, there is a correlation between the view mailer name and the template file name.
-It's the translation of the name into a path: from `Mailers::ForgotPassword` to `forgot_password`.
-
-The remaining part is made of multiple file extensions.
-The first is relative to the **_format_** and the latter is for the **_template engine_**.
-
-**Hanami only accepts `html` and `txt` formats for emails.**
-
-
-For a given mailer named Mailers::ForgotPassword
, there must be at least one template forgot_password.[format].[engine]
under the mailers templates directory.
-
-
-### Custom Template
-
-If we want to associate a different template to a mailer, we can use `template`.
-
-```ruby
-# lib/bookshelf/mailers/forgot_password.rb
-class Mailers::ForgotPassword
- include Hanami::Mailer
- template 'send_password'
-end
-```
-
-Our view will look for `lib/bookshelf/mailers/templates/send_password.*` template.
-
-## Engines
-
-Hanami looks at the last extension of a template file name to decide which engine to use (eg `welcome.html.erb` will use ERb).
-The builtin rendering engine is [ERb](http://en.wikipedia.org/wiki/ERuby), but Hanami supports countless rendering engines out of the box.
-
-This is a list of the supported engines.
-They are listed in order of **higher precedence**, for a given extension.
-For instance, if [ERubis](http://www.kuwata-lab.com/erubis/) is loaded, it will be preferred over ERb to render `.erb` templates.
-
-
-
- Engine
- Extensions
-
-
- Erubis
- erb, rhtml, erubis
-
-
- ERb
- erb, rhtml
-
-
- Redcarpet
- markdown, mkd, md
-
-
- RDiscount
- markdown, mkd, md
-
-
- Kramdown
- markdown, mkd, md
-
-
- Maruku
- markdown, mkd, md
-
-
- BlueCloth
- markdown, mkd, md
-
-
- Asciidoctor
- ad, adoc, asciidoc
-
-
- Builder
- builder
-
-
- CSV
- rcsv
-
-
- CoffeeScript
- coffee
-
-
- WikiCloth
- wiki, mediawiki, mw
-
-
- Creole
- wiki, creole
-
-
- Etanni
- etn, etanni
-
-
- Haml
- haml
-
-
- Less
- less
-
-
- Liquid
- liquid
-
-
- Markaby
- mab
-
-
- Nokogiri
- nokogiri
-
-
- Plain
- html
-
-
- RDoc
- rdoc
-
-
- Radius
- radius
-
-
- RedCloth
- textile
-
-
- Sass
- sass
-
-
- Scss
- scss
-
-
- Slim
- slim
-
-
- String
- str
-
-
- Yajl
- yajl
-
-
-
-In order to use a different template engine we need to bundle the gem and to use the right file extension.
-
-```haml
-# lib/bookshelf/mailers/templates/welcome.html.haml
-%h1 Welcome
-```
-
-## Templates Directory
-
-Templates are located in the default directory `mailers/templates`, located under an application's directory `lib/bookshelf`, where `bookshelf` is the name of our application.
-If we want to customize this location, we can set a different value in Hanami::Mailer configuration.
-
-```ruby
-# lib/bookshelf.rb
-# ...
-
-Hanami::Mailer.configure do
- # ...
- root 'path/to/templates'
-end.load!
-```
-
-The application will now look for templates under `path/to/templates`.
diff --git a/source/guides/1.1/mailers/testing.md b/source/guides/1.1/mailers/testing.md
deleted file mode 100644
index 1f9251f42..000000000
--- a/source/guides/1.1/mailers/testing.md
+++ /dev/null
@@ -1,32 +0,0 @@
----
-title: Guides - Mailers Testing
-version: 1.1
----
-
-# Testing
-
-During development and testing we don't want to accidentally send emails to the real world.
-The [delivery method](/guides/1.1/mailers/delivery) for these two envs is set to `:test`.
-
-In order to assert that a mailer sent a message, we can look at `Hanami::Mailer.deliveries`.
-It's an array of messages that the framework pretended to deliver during a test.
-Please make sure to **clear** them in testing setup.
-
-```ruby
-# spec/bookshelf/mailers/welcome_spec.rb
-require 'spec_helper'
-
-describe Mailers::Welcome do
- before { Hanami::Mailer.deliveries.clear }
-
- let(:user) { ... }
-
- it "delivers welcome email" do
- Mailers::Welcome.deliver(user: user)
- mail = Hanami::Mailer.deliveries.last
-
- expect(mail.to).to eq([user.email])
- expect(mail.body.encoded).to eq("Hello, #{ user.name }")
- end
-end
-```
diff --git a/source/guides/1.1/migrations/alter-table.md b/source/guides/1.1/migrations/alter-table.md
deleted file mode 100644
index 77faa4a53..000000000
--- a/source/guides/1.1/migrations/alter-table.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Guides - Migrations Alter Tables
-version: 1.1
----
-
-# Alter Tables
-
-The following methods are available for table alterations:
-
- * `#add_column` (see `#column` for usage)
- * `#drop_column`
- * `#rename_column` (the first argument is the **old name**, while the second is the **new name**)
- * `#add_index` (see `#index` for usage)
- * `#drop_index`
- * `#add_primary_key` (see `#primary_key` for usage)
- * `#add_foreign_key` (see `#foreign_key` for usage)
- * `#add_constraint` (see `#constraint` for usage)
- * `#drop_constraint` (accepts the **name** of the constraint as argument)
- * `#add_unique_constraint`
- * `#set_column_default` (accepts the **name** of the column and the **default value** as comma separated args)
- * `#set_column_type` (accepts the **name** of the column and the **new type** as comma separated args)
- * `#set_column_allow_null` (accepts the **name** of the column)
- * `#set_column_not_null` (accepts the **name** of the column)
-
-Those methods accept the **name of the target table as first argument**, then the other args.
-There is a convenient shortcut for this: `#alter_table`. It accepts the **name of the table** and a **block** that describes the alterations.
-
-The following syntaxes are **equivalent**.
-
-```ruby
-Hanami::Model.migration do
- change do
- add_column :users, :email, String, null: false, unique: true
- set_column_default :users, :visits_counts, default: 0
- end
-end
-```
-
-The code above can be DRY'd with:
-
-```ruby
-Hanami::Model.migration do
- change do
- alter_table :users do
- # `users` table is implicit within this block, so it can be omitted.
- add_column :email, String, null: false, unique: true
- set_column_default :visits_counts, default: 0
- end
- end
-end
-```
-
-## Rename Table
-
-Tables can be renamed via `#rename_table`. It accepts the **old name** and the **new name** as arguments.
-
-```ruby
-rename_table :users, :people
-```
-
-## Drop Table
-
-Tables can be dropped via `#drop_table`. It accepts the **name** as argument.
-
-```ruby
-drop_table :users
-```
-
-Safe operation can be performed via `#drop_table?`. It drops the table only if it exists.
diff --git a/source/guides/1.1/migrations/create-table.md b/source/guides/1.1/migrations/create-table.md
deleted file mode 100644
index 509191042..000000000
--- a/source/guides/1.1/migrations/create-table.md
+++ /dev/null
@@ -1,152 +0,0 @@
----
-title: Guides - Migrations Create Tables
-version: 1.1
----
-
-# Create Tables
-
-A table is defined via `#create_table`. This method accepts two arguments: the **name** and a **block** that expresses the design.
-
-Safe operation can be performed via `#create_table?`. It only creates the table if it doesn't exist.
-Force operation can be performed via `#create_table!`. It drops the existing table and creates a new one from scratch.
-**These operations shouldn't be used in migrations**.
-
-## Column Definition
-
-To define a column we use `#column`, followed by the **name**, the **type** and **options**.
-The name must be a unique identifier within the table.
-
-The type can be a Ruby type (e.g. `String`), a symbol that represents a Ruby type (e.g. `:string`), or a string that represents the raw database type (e.g. `"varchar(255)"`). The only one exception in case of symbol is :Bignum. Using the symbol :Bignum as a type will use the appropriate 64-bit integer type for the database you are using.
-
-## Type Definition
-
-The following Ruby types are supported:
-
- * `String` (`varchar(255)`)
- * `Numeric` (`numeric`)
- * `Fixnum` (`integer`)
- * `Integer` (`integer`)
- * `:Bignum` (`bigint`) # Note: use this type as a symbol, since Ruby 2.4.0 removed Bignum class
- * `Float` (`double precision`)
- * `BigDecimal` (`numeric`)
- * `Date` (`date`)
- * `DateTime` (`timestamp`)
- * `Time` (`timestamp`)
- * `TrueClass` (`boolean`)
- * `FalseClass` (`boolean`)
- * `File` (`blob`)
-
-Their translation from Ruby types to database types may vary from database to database.
-
-### Options
-
-It supports the following options:
-
- * `:default` (default value)
- * `:index` (create an index for the column)
- * `:null` (allow NULL values or not)
- * `:primary_key` (make the column primary key for the table)
- * `:unique` (add a uniqueness constraint for the column)
-
-
- Note that Hanami natively supports PostgreSQL data types .
- Learn more about them in the dedicated article .
-
-
-## Primary Key
-
-We can define **primary keys** with the following syntaxes:
-
-```ruby
-column :id, Integer, null: false, primary_key: true
-# or just use this shortcut
-primary_key :id
-```
-
-## Foreign Keys
-
-**Foreign keys** are defined via `#foreign_key`, where we specify the **name** of the column, the **referenced table**, and a set of **options**.
-The following example creates an `author_id` column (integer) for `books` and adds a foreign key.
-
-```ruby
-create_table :books do
- # ...
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-end
-```
-
-### Options
-
-It accepts the following options:
-
- * `:deferrable` (make the constraint check deferrable at the end of a transaction)
- * `:key` (the column in the associated table that this column references. Unnecessary if this column references the primary key of the associated table)
- * `:null` (allow NULL values or not)
- * `:type` (the column type)
- * `:on_delete` (action to take if the referenced record is deleted: `:restrict`, `:cascade`, `:set_null`, or `:set_default`)
- * `:on_update` (action to take if the referenced record is updated: `:restrict`, `:cascade`, `:set_null`, or `:set_default`)
-
-
-## Indexes
-
-Indexes are defined via `#index`. It accepts the **name(s)** of the column(s), and a set of **options**.
-
-```ruby
-create_table :stores do
- # ...
- column :code, Integer, null: false
- column :lat, Float
- column :lng, Float
-
- index :code, unique: true
- index [:lat, :lng], name: :stores_coords_index
-end
-```
-
-### Options
-
-It accepts the following options:
-
- * `:unique` (uniqueness constraint)
- * `:name` (custom name)
- * `:type` (the type of index, supported by some databases)
- * `:where` (partial index, supported by some databases)
-
-
-## Constraints
-
-We can define constraints on columns via `#constraint`. It accepts a **name** and a **block**.
-
-```ruby
-create_table :users do
- # ...
- column :age, Integer
- constraint(:adult_constraint) { age > 18 }
-end
-```
-
-Please note that the block is evaluated in the context of the database engine, **complex Ruby code doesn't work**.
-Database functions are mapped to Ruby functions, but this reduces the portability of the migration.
-
-```ruby
-create_table :users do
- # ...
- column :password, String
- constraint(:password_length_constraint) { char_length(password) >= 8 }
-end
-```
-
-## Checks
-
-Checks are similar to constraints, but they accept an **anonymous block** or a **SQL raw string**.
-
-```ruby
-create_table :users do
- # ...
- column :age, Integer
- column :role, String
-
- check { age > 18 }
- check %(role IN('contributor', 'manager', 'owner'))
-end
-```
diff --git a/source/guides/1.1/migrations/overview.md b/source/guides/1.1/migrations/overview.md
deleted file mode 100644
index cf2b9136b..000000000
--- a/source/guides/1.1/migrations/overview.md
+++ /dev/null
@@ -1,92 +0,0 @@
----
-title: Guides - Migrations
-version: 1.1
----
-
-# Migrations
-
-Migrations are a feature that allows to manage database schema via Ruby.
-They come with some [command line facilities](/guides/1.1/command-line/database) that allow to perform database operations or to [generate](/guides/1.1/command-line/generators/#migrations) migrations.
-
-Migrations are only available if our application uses the [SQL adapter](/guides/1.1/models/overview).
-
-## Anatomy Of A Migration
-
-Migrations are Ruby files stored by default under `db/migrations`.
-Their name is composed by a UTC timestamp and a snake case name (eg `db/migrations/20150621165604_create_books.rb`).
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
- foreign_key :author_id, :authors, on_delete: :cascade, null: false
-
- column :code, String, null: false, unique: true, size: 128
- column :title, String, null: false
- column :price, Integer, null: false, default: 100 # cents
-
- check { price > 0 }
- end
- end
-end
-```
-
-We use a `create_table` block to define the schema of that table.
-
-The first line is `primary_key :id`, which is a shortcut to create an autoincrement integer column.
-
-There is a `foreign key` definition with cascade deletion.
-The first argument is the name of the local column (`books.author_id`), while the second is the referenced table.
-
-Then we have three lines for columns.
-The first argument that we pass to `column` is the name, then the type.
-The type can be a **Ruby type** such as `String` or `Integer` or a string that represents the **native database type** (eg. `"varchar(32)"` or `"text[]"`).
-
-As a last optional argument there is a Hash that specifies some extra details for the column. For instance NULL or uniqueness constraints, the size (for strings) or the default value.
-
-The final line defines a database **check** to ensure that price will always be greater than zero.
-
-## Up/Down
-
-When we "migrate" a database we are going into an _"up"_ direction because we're adding alterations to it.
-Migrations modifications can be rolled back (_"down"_ direction).
-
-When we use `change` in our migrations, we're implicitly describing _"up"_ modifications.
-Their counterpart can be inferred by `Hanami::Model` when we migrate _"down"_ our database.
-
-Imagine we have the following code:
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :books do
- # ...
- end
- end
-end
-```
-
-When we use `create_table`, Hanami::Model will use `drop_table` in case we want to rollback this migration.
-
-In case we want to have concrete code for our _"down"_ policy, we can use `up` and `down` blocks.
-
-```ruby
-Hanami::Model.migration do
- up do
- create_table :books do
- # ...
- end
- end
-
- down do
- drop_table :books
- end
-end
-```
-
-**To learn how to use migrations in command line, please have a look at [this article](/guides/1.1/command-line/database/#migrate).**
-
-## References
-
-Hanami::Model uses [Sequel](http://sequel.jeremyevans.net/) under the hood as database migration engine. If there is any aspect that isn't covered by our documentation or tests, please refer to [Sequel documentation](http://sequel.jeremyevans.net/rdoc/files/doc/schema_modification_rdoc.html).
diff --git a/source/guides/1.1/models/database-configuration.md b/source/guides/1.1/models/database-configuration.md
deleted file mode 100644
index e958951a5..000000000
--- a/source/guides/1.1/models/database-configuration.md
+++ /dev/null
@@ -1,46 +0,0 @@
----
-title: Guides - Database Configuration
-version: 1.1
----
-
-# Database Configuration
-
-Before starting your server, you need to configure the database link in .env*
files.
-
-Open this file for each environment and update DATABASE_URL
for your database.
-
-Setup database variable for the development environment:
-
-```
-# .env.development
-DATABASE_URL="database_type://username:password@localhost/bookshelf_development"
-```
-
-Setup database variable for the test environment:
-
-```
-# .env.test
-DATABASE_URL="database_type://username:password@localhost/bookshelf_test"
-```
-
-For jdbc urls you can't set username and password to the left of @ you have to set them as parameters in the url:
-
-```
-DATABASE_URL="jdbc-database_type://localhost/bookshelf_test?user=username&password=password"
-```
-
-## Setup your database
-
-After your database variables setup is done you need to create the database and run the migrations before being able to launch a development server.
-
-In your terminal, enter:
-
-```
-% bundle exec hanami db prepare
-```
-
-To setup your test environment database, enter:
-
-```
-% HANAMI_ENV=test bundle exec hanami db prepare
-```
diff --git a/source/guides/1.1/models/overview.md b/source/guides/1.1/models/overview.md
deleted file mode 100644
index 8b1f4a622..000000000
--- a/source/guides/1.1/models/overview.md
+++ /dev/null
@@ -1,73 +0,0 @@
----
-title: Guides - Models Overview
-version: 1.1
----
-
-# Models
-
-Hanami's model domain is implemented in a way that separates the behavior that we want to express ([entities](/guides/1.1/models/entities)) from the persistence layer ([repositories](/guides/1.1/models/repositories) and database).
-This design helps keep the interface of our objects small and therefore keeps them fast and reusable.
-
-## Basic Usage
-
-To explain the basic usage, we use a PostgreSQL database.
-
-As first step, we generate the model:
-
-```shell
-% bundle exec hanami generate model book
- create lib/bookshelf/entities/book.rb
- create lib/bookshelf/repositories/book_repository.rb
- create db/migrations/20170406230335_create_books.rb
- create spec/bookshelf/entities/book_spec.rb
- create spec/bookshelf/repositories/book_repository_spec.rb
-```
-
-The generator gives us an entity, a repository, a migration, and accompanying test files.
-
-This is the generated entity:
-
-```ruby
-class Book < Hanami::Entity
-end
-```
-
-While this is the generated repository:
-
-```ruby
-class BookRepository < Hanami::Repository
-end
-```
-
-Let's edit the migration with the following code:
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :books do
- primary_key :id
- column :title, String
- column :created_at, DateTime
- column :updated_at, DateTime
- end
- end
-end
-```
-
-Now we need to prepare the database to use it:
-
-```shell
-% bundle exec hanami db prepare
-```
-
-We're ready to use our repository:
-
-```shell
-% bundle exec hanami console
-irb(main):001:0> book = BookRepository.new.create(title: "Hanami")
-=> #1, :title=>"Hanami", :created_at=>2016-11-13 15:49:14 UTC, :updated_at=>2016-11-13 15:49:14 UTC}>
-```
-
----
-
-Learn more about [repositories](/guides/1.1/repositories/overview), [entities](/guides/1.1/entities/overview), [migrations](/guides/1.1/migrations/overview), and [database CLI commands](/guides/1.1/command-line/database).
diff --git a/source/guides/1.1/models/use-your-own-orm.md b/source/guides/1.1/models/use-your-own-orm.md
deleted file mode 100644
index 2bde13468..000000000
--- a/source/guides/1.1/models/use-your-own-orm.md
+++ /dev/null
@@ -1,19 +0,0 @@
----
-title: Guides - Use Your Own ORM
-version: 1.1
----
-
-# Use Your Own ORM
-
-Hanami components are decoupled each other.
-This level of separation allows you to use the ORM (data layer) of your choice.
-
-Here's how to do it:
-
- 1. Edit your `Gemfile`, remove `hanami-model`, add the gem(s) of your ORM and run `bundle install`.
- 2. Remove `lib/` directory (eg. `rm -rf lib`).
- 3. Edit `config/environment.rb`, then remove `require_relative '../lib/bookshelf'` and `model` block in `Hanami.configure`
- 4. Edit `Rakefile` and remove `require 'hanami/rake_tasks'`.
-
-Please notice that if `hanami-model` is removed from the project features like [database commands](/guides/1.1/command-line/database) and [migrations](/guides/1.1/migrations/overview) aren't available.
-
diff --git a/source/guides/1.1/projects/code-reloading.md b/source/guides/1.1/projects/code-reloading.md
deleted file mode 100644
index cf59e2d2b..000000000
--- a/source/guides/1.1/projects/code-reloading.md
+++ /dev/null
@@ -1,37 +0,0 @@
----
-title: Guides - Code Reloading
-version: 1.1
----
-
-# Code Reloading
-
-_Code reloading_ allows us to edit code and see the changes with a browser refresh, without needing to stop and restart the [server](/guides/1.1/command-line/applications).
-
-## Development Environment
-
-This is a development-only feature.
-Hanami uses `shotgun` Ruby gem to reload the code as-needed.
-New generated projects have this entry in their `Gemfile`:
-
-```ruby
-group :development do
- # Code reloading
- # See: http://hanamirb.org/guides/1.1/projects/code-reloading
- gem 'shotgun'
-end
-```
-
-Unfortunately, `shotgun` requires that the current environment supports `fork(2)`.
-JRuby and Windows don't support it.
-If this is your case, `shotgun` is not compatible with your development environment, then you can remove that entry from the `Gemfile` or start the server with the `--no-code-reloading` argument.
-
-## Other Environments
-
-Hanami doesn't implement _code reloading_ in its core.
-
-The framework doesn't know about this feature, it just uses Ruby to load the code and execute it. It's `shotgun` that makes _code reloading_ possible, by wrapping Hanami projects' code.
-
-Because `shotgun` is only enabled in development, all the other environments don't have this _code reloading_ feature.
-By excluding this feature from the core of the framework, we make sure that Hanami projects don't mess with Ruby's code loading mechanisms in production.
-
-In other words, once the code is loaded in production, it isn't changed anymore.
diff --git a/source/guides/1.1/projects/initializers.md b/source/guides/1.1/projects/initializers.md
deleted file mode 100644
index 03a390cf5..000000000
--- a/source/guides/1.1/projects/initializers.md
+++ /dev/null
@@ -1,35 +0,0 @@
----
-title: Guides - Project Initializers
-version: 1.1
----
-
-# Initializers
-
-A project can **optionally** have one or more custom initializers.
-
-
- Initializers are optional
-
-
-An initializer is a Ruby file used to setup third-party libraries or some other aspect of the code.
-
-They are run as the **last** thing after the dependencies, the framework and the project code are loaded, but **before** the server or the console is started.
-
-For instance, if we want to setup [Bugsnag](https://bugsnag.com) for our project we can do:
-
-```ruby
-# config/initializers/bugsnag.rb
-require 'bugsnag'
-
-Bugsnag.configure do |config|
- config.api_key = ENV['BUGSNAG_API_KEY']
-end
-```
-
-
- Project initializers must be added under config/initializers
.
-
-
-
- Initializers are executed in alphabetical order.
-
diff --git a/source/guides/1.1/projects/logging.md b/source/guides/1.1/projects/logging.md
deleted file mode 100644
index b3b4ebe46..000000000
--- a/source/guides/1.1/projects/logging.md
+++ /dev/null
@@ -1,164 +0,0 @@
----
-title: Guides - Logging
-version: 1.1
----
-
-# Logging
-
-Each project has a global logger available at `Hanami.logger` that can be used like this: `Hanami.logger.debug "Hello"`
-
-It can be configured in `config/environment.rb`
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :development do
- logger level: :info
- end
-
- environment :production do
- logger level: :info, formatter: :json
-
- # ...
- end
-end
-```
-
-By default it uses standard output because it's a [best practice](http://12factor.net/logs) that most hosting SaaS companies [suggest using](https://devcenter.heroku.com/articles/rails4#logging-and-assets).
-
-If you want to use a file, pass `stream: 'path/to/file.log'` as an option.
-
-## Filter sensitive informations
-
-Hanami automatically logs the body of non-GET HTTP requests.
-
-When a user submits a form, all the fields and their values will appear in the log:
-
-```shell
-[bookshelf] [INFO] [2017-08-11 18:17:54 +0200] HTTP/1.1 POST 302 ::1 /signup 5 {"signup"=>{"username"=>"jodosha", "password"=>"secret", "password_confirmation"=>"secret", "bio"=>"lorem"}} 0.00593
-```
-
-To avoid sensitive informations to be logged, you can filter them:
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
- environment :development do
- logger level: :debug, filter: %w[password password_confirmation]
- end
-end
-```
-
-Now the output will be:
-
-```shell
-[bookshelf] [INFO] [2017-08-11 18:17:54 +0200] HTTP/1.1 POST 302 ::1 /signup 5 {"signup"=>{"username"=>"jodosha", "password"=>"[FILTERED]", "password_confirmation"=>"[FILTERED]", "bio"=>"lorem"}} 0.00593
-```
-
-It also supports fine grained patterns to disambiguate params with the same name.
-For instance, we have a billing form with street number and credit card number, and we want only to filter the credit card:
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
- environment :development do
- logger level: :debug, filter: %w[credit_card.number]
- end
-end
-```
-
-```shell
-[bookshelf] [INFO] [2017-08-11 18:43:04 +0200] HTTP/1.1 PATCH 200 ::1 /billing 2 {"billing"=>{"name"=>"Luca", "address"=>{"street"=>"Centocelle", "number"=>"23", "city"=>"Rome"}, "credit_card"=>{"number"=>"[FILTERED]"}}} 0.009782
-```
-
-Note that `billing => address => number` wasn't filtered while `billing => credit_card => number` was filtered instead.
-
-## Arbitrary Arguments
-
-You can speficy [arbitrary arguments](https://ruby-doc.org/stdlib/libdoc/logger/rdoc/Logger.html#class-Logger-label-How+to+create+a+logger), that are compatible with Ruby's `Logger`.
-
-Here's how to setup daily log rotation:
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :production do
- logger 'daily', level: :info, formatter: :json, stream: 'log/production.log'
-
- # ...
- end
-end
-```
-
-Alternatively, you can decide to put a limit to the number of files (let's say `10`) and the size of each file (eg `1,024,000` bytes, aka `1` megabyte):
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :production do
- logger 10, 1_024_000, level: :info, formatter: :json, stream: 'log/production.log'
-
- # ...
- end
-end
-```
-
-## Custom Loggers
-
-You can specify a custom logger in cases where you desire different logging behaviour. For example,
-the [Timber logger](https://github.com/timberio/timber-ruby):
-
-```ruby
-# config/environment.rb
-# ...
-
-Hanami.configure do
- # ...
-
- environment :production do
- logger Timber::Logger.new(STDOUT)
-
- # ...
- end
-end
-```
-
-Use this logger as normal via `Hanami.logger`. It's important to note that any logger chosen
-must conform to the default `::Logger` interface.
-
-
-## Automatic Logging
-
-All HTTP requests, SQL queries, and database operations are automatically logged.
-
-When a project is used in development mode, the logging format is human readable:
-
-```ruby
-[bookshelf] [INFO] [2017-02-11 15:42:48 +0100] HTTP/1.1 GET 200 127.0.0.1 /books/1 451 0.018576
-[bookshelf] [INFO] [2017-02-11 15:42:48 +0100] (0.000381s) SELECT "id", "title", "created_at", "updated_at" FROM "books" WHERE ("book"."id" = '1') ORDER BY "books"."id"
-```
-
-For production environment, the default format is JSON.
-JSON is parseable and more machine-oriented. It works great with log aggregators or SaaS logging products.
-
-```json
-{"app":"bookshelf","severity":"INFO","time":"2017-02-10T22:31:51Z","http":"HTTP/1.1","verb":"GET","status":"200","ip":"127.0.0.1","path":"/books/1","query":"","length":"451","elapsed":0.000391478}
-```
diff --git a/source/guides/1.1/projects/rake.md b/source/guides/1.1/projects/rake.md
deleted file mode 100644
index 62816eaae..000000000
--- a/source/guides/1.1/projects/rake.md
+++ /dev/null
@@ -1,65 +0,0 @@
----
-title: Guides - Rake Tasks
-version: 1.1
----
-
-# Rake Tasks
-
-Hanami ships with default Rake tasks that can be used as _prerequisites_ by developers to build their own tasks.
-
-```shell
-% bundle exec rake -T
-rake environment # Load the full project
-rake test # Run tests (for Minitest)
-rake spec # Run tests (for RSpec)
-```
-
-## Environment
-
-Use this as a Rake task prerequisite when we need to access project code (eg. entities, actions, views, etc..)
-
-### Example
-
-Imagine we want to build a Rake task that is able to access project code (eg. a repository)
-
-```ruby
-# Rakefile
-
-task clear_users: :environment do
- UserRepository.new.clear
-end
-```
-
-```shell
-bundle exec rake clear_users
-```
-
-## Test / Spec
-
-This is the default Rake task, which runs the test suite
-
-The following commands are equivalent:
-
-```shell
-% bundle exec rake
-```
-
-```shell
-% bundle exec rake test
-```
-
-
- The :test
(or :spec
in case you generated the application with --test=rspec
switch) Rake task is the default.
-
-
-## Ruby Server Hosting Ecosystem Compatibility
-
-Many Software as a Service (SaaS) of the Ruby server hosting ecosystem are modeled after Ruby on Rails.
-For instance, Heroku expects to find the following Rake tasks in a Ruby application:
-
- * `db:migrate`
- * `assets:precompile`
-
-For Heroku, there isn't a way to customize the deploy, so we're supporting these "standard" Rake tasks from Ruby on Rails.
-
-**If you are in control of your deployment, don't rely on these Rake tasks, but please use `hanami` [command line](/guides/1.1/command-line/database), instead.**
diff --git a/source/guides/1.1/projects/security.md b/source/guides/1.1/projects/security.md
deleted file mode 100644
index f112e9cd4..000000000
--- a/source/guides/1.1/projects/security.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: Guides - Project Security
-version: 1.1
----
-
-# Security
-
-Modern web development has many challenges, and of those security is both very important and often under-emphasized.
-
-Hanami provides ways to secure from most common vulnerabilities. Security options can be configured in application.rb
.
-
-# X-Frame-Options
-
-X-Frame-Options is a HTTP header supported by modern browsers. It determines if a web page can or cannot be included via *<frame>* and *<iframe>* tags by untrusted domains.
-
-Web applications can send this header to prevent Clickjacking attacks:
-
-```ruby
-# Denies all untrusted domains (default)
-security.x_frame_options 'DENY'
-```
-
-```ruby
-# Allows iframes on example.com
-security.x_frame_options 'ALLOW-FROM https://example.com/'
-```
-
-# X-Content-Type-Options
-
-X-Content-Type-Options prevents browsers from interpreting files as something else than declared by the content type in the HTTP headers.
-
-```ruby
-# Will prevent the browser from MIME-sniffing a response away from the declared content-type (default)
-security.x_content_type_options 'nosniff'
-```
-
-# X-XSS-Protection
-
-X-XSS-Protection is a HTTP header to determine the behavior of the browser in case an XSS attack is detected.
-
-
-```ruby
-# Filter enabled. Rather than sanitize the page, when a XSS attack is detected,
-# the browser will prevent rendering of the page (default)
-security.x_xss_protection '1; mode=block'
-```
-
-```ruby
-# Filter disabled
-security.x_xss_protection '0'
-```
-
-```ruby
-# Filter enabled. If a cross-site scripting attack is detected, in order to stop the attack,
-# the browser will sanitize the page
-security.x_xss_protection '1'
-```
-
-```ruby
-# The browser will sanitize the page and report the violation.
-# This is a Chromium function utilizing CSP violation reports to send details to a URI of your choice
-security.x_xss_protection '1; report=http://[YOURDOMAIN]/your_report_URI'
-```
-
-# Content-Security-Policy
-Content-Security-Policy (CSP) is a HTTP header supported by modern browsers. It determines trusted sources of execution for dynamic
-contents (JavaScript) or other web related assets: stylesheets, images, fonts, plugins, etc.
-
-Web applications can send this header to mitigate Cross Site Scripting (XSS) attacks.
-
-The default value allows images, scripts, AJAX, fonts and CSS from the same origin, and does not allow any
-other resources to load (eg object, frame, media, etc).
-
-Inline JavaScript is NOT allowed. To enable it, please use: script-src 'unsafe-inline'
.
-
-Default value is:
-
-```ruby
-security.content_security_policy %{
- form-action 'self';
- frame-ancestors 'self';
- base-uri 'self';
- default-src 'none';
- script-src 'self';
- connect-src 'self';
- img-src 'self' https: data:;
- style-src 'self' 'unsafe-inline' https:;
- font-src 'self';
- object-src 'none';
- plugin-types application/pdf;
- child-src 'self';
- frame-src 'self';
- media-src 'self'
-}
-```
diff --git a/source/guides/1.1/repositories/overview.md b/source/guides/1.1/repositories/overview.md
deleted file mode 100644
index 2c81c2bbb..000000000
--- a/source/guides/1.1/repositories/overview.md
+++ /dev/null
@@ -1,257 +0,0 @@
----
-title: Guides - Repositories Overview
-version: 1.1
----
-
-# Repositories
-
-An object that mediates between entities and the persistence layer.
-It offers a standardized API to query and execute commands on a database.
-
-A repository is **storage independent**, all the queries and commands are
-delegated to the current adapter.
-
-This architecture has several advantages:
-
- * Applications depend on a standard API, instead of low level details
- ([Dependency Inversion](https://en.wikipedia.org/wiki/Dependency_inversion_principle) principle)
-
- * Applications depend on a stable API, that doesn't change if the
- storage changes
-
- * Developers can postpone storage decisions
-
- * Confines persistence logic to a low level
-
- * Multiple data sources can easily coexist in an application
-
-
- As of the current version, Hanami only supports SQL databases.
-
-
-## Interface
-
-When a class inherits from `Hanami::Repository`, it will receive the following interface:
-
- * `#create(data)` β Create a record for the given data and return an entity
- * `#update(id, data)` β Update the record corresponding to the id and return the updated entity
- * `#delete(id)` β Delete the record corresponding to the given entity
- * `#all` - Fetch all the entities from the collection
- * `#find(id)` - Fetch an entity from the collection by its ID
- * `#first` - Fetch the first entity from the collection
- * `#last` - Fetch the last entity from the collection
- * `#clear` - Delete all the records from the collection
-
-**A collection is a homogenous set of records.**
-It corresponds to a table for a SQL database or to a MongoDB collection.
-
-```ruby
-repository = BookRepository.new
-
-book = repository.create(title: "Hanami")
- # => #1, :title=>"Hanami", :created_at=>2016-11-13 16:02:37 UTC, :updated_at=>2016-11-13 16:02:37 UTC}>
-
-book = repository.find(book.id)
- # => #1, :title=>"Hanami", :created_at=>2016-11-13 16:02:37 UTC, :updated_at=>2016-11-13 16:02:37 UTC}>
-
-book = repository.update(book.id, title: "Hanami Book")
- # => #1, :title=>"Hanami Book", :created_at=>2016-11-13 16:02:37 UTC, :updated_at=>2016-11-13 16:03:34 UTC}>
-
-repository.delete(book.id)
-
-repository.find(book.id)
- # => nil
-```
-
-## Private Queries
-
-**All the queries are private**.
-This decision forces developers to define intention revealing API, instead of leaking storage API details outside of a repository.
-
-Look at the following code:
-
-```ruby
-BookRepository.new.where(author_id: 23).order(:published_at).limit(8)
-```
-
-This is **bad** for a variety of reasons:
-
- * The caller has an intimate knowledge of the internal mechanisms of the Repository.
-
- * The caller works on several levels of abstraction.
-
- * It doesn't express a clear intent, it's just a chain of methods.
-
- * The caller can't be easily tested in isolation.
-
- * If we change the storage, we are forced to change the code of the caller(s).
-
-There is a better way:
-
-```ruby
-# lib/bookshelf/repositories/book_repository.rb
-class BookRepository < Hanami::Repository
- def most_recent_by_author(author, limit: 8)
- books
- .where(author_id: author.id)
- .order(:published_at)
- .limit(limit)
- end
-end
-```
-
-This is a **huge improvement**, because:
-
- * The caller doesn't know how the repository fetches the entities.
-
- * The caller works on a single level of abstraction. It doesn't even know about records, only works with entities.
-
- * It expresses a clear intent.
-
- * The caller can be easily tested in isolation. It's just a matter of stubbing this method.
-
- * If we change the storage, the callers aren't affected.
-
-
-
- Hanami queries are based on gems from ROM project, namely
- rom-repository
and rom-sql
.
- The gem rom-sql
is itself based on Sequel project.
-
-
- Learn more on how to craft queries with
- ROM
- and Sequel .
-
-
-
-## Timestamps
-
-To have a track of when a record has been created or updated is important when running a project in production.
-
-When creating a new table, if we add the following columns, a repository will take care of keeping the values updated.
-
-```ruby
-Hanami::Model.migration do
- up do
- create_table :books do
- # ...
- column :created_at, DateTime
- column :updated_at, DateTime
- end
- end
-end
-```
-
-```ruby
-repository = BookRepository.new
-
-book = repository.create(title: "Hanami")
-
-book.created_at # => 2016-11-14 08:20:44 UTC
-book.updated_at # => 2016-11-14 08:20:44 UTC
-
-book = repository.update(book.id, title: "Hanami Book")
-
-book.created_at # => 2016-11-14 08:20:44 UTC
-book.updated_at # => 2016-11-14 08:22:40 UTC
-```
-
-
- When a database table has created_at
and updated_at
timestamps, a repository will automatically update their values.
-
-
-
- Timestamps are on UTC timezone.
-
-
-## Legacy Databases
-
-By default, a repository performs auto-mapping of corresponding database table and creates an [automatic schema](/guides/1.1/models/entities#automatic-schema) for the associated entity.
-
-When working with legacy databases we can resolve the naming mismatch between the table name, the columns, with repositories defaults and entities attributes.
-
-Let's say we have a database table like this:
-
-```sql
-CREATE TABLE t_operator (
- operator_id integer NOT NULL,
- s_name text
-);
-```
-
-We can setup our repository with the following code:
-
-```ruby
-# lib/bookshelf/repositories/operator_repository.rb
-class OperatorRepository < Hanami::Repository
- self.relation = :t_operator
-
- mapping do
- attribute :id, from: :operator_id
- attribute :name, from: :s_name
- end
-end
-```
-
-While the entity can stay with the basic setup:
-
-```ruby
-# lib/bookshelf/entities/operator.rb
-class Operator < Hanami::Entity
-end
-```
-
----
-
-The entity now gets the mapping we defined in the repository:
-
-```ruby
-operator = Operator.new(name: "Jane")
-operator.name # => "Jane"
-```
-
-The repository can use the same mapped attributes:
-
-```ruby
-operator = OperatorRepository.new.create(name: "Jane")
- # => #1, :name=>"Jane"}>
-```
-
-## Count
-
-Count is a concept not generally available to all the databases. SQL databases have it, but others don't.
-
-You can define a method, if you're using a SQL database:
-
-```ruby
-class BookRepository < Hanami::Repository
- def count
- books.count
- end
-end
-```
-
-Or you can expose specific conditions:
-
-```ruby
-class BookRepository < Hanami::Repository
- # ...
-
- def on_sale_count
- books.where(on_sale: true).count
- end
-end
-```
-
-If you want to use raw SQL you can do:
-
-```ruby
-class BookRepository < Hanami::Repository
- # ...
-
- def old_books_count
- books.read("SELECT id FROM books WHERE created_at < (NOW() - 1 * interval '1 year')").count
- end
-end
-```
diff --git a/source/guides/1.1/repositories/postgresql.md b/source/guides/1.1/repositories/postgresql.md
deleted file mode 100644
index 753b2999f..000000000
--- a/source/guides/1.1/repositories/postgresql.md
+++ /dev/null
@@ -1,103 +0,0 @@
----
-title: "Guides - Repositories: PostgreSQL"
-version: 1.1
----
-
-# PostgreSQL
-
-Hanami natively supports PostgreSQL data types.
-
-Please check your PostgreSQL version for the available features.
-
-## UUID
-
-Here's how to use UUID for a column:
-
-```ruby
-# db/migrations/20161113184557_create_projects.rb
-Hanami::Model.migration do
- up do
- execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
-
- create_table :projects do
- primary_key :id
- column :name, String
- column :token, 'uuid'
- end
- end
-
- down do
- drop_table :projects
- execute 'DROP EXTENSION IF EXISTS "uuid-ossp"'
- end
-end
-```
-
-```ruby
-require "securerandom"
-
-ProjectRepository.new.create(name: "Hanami", token: SecureRandom.uuid)
- # => #1, :name=>"Hanami", :token=>"0aa7ecff-15e4-4aa4-8c00-0e699e2c66f0"}>
-```
-
-### UUID as Primary Key
-
-```ruby
-Hanami::Model.migration do
- up do
- execute 'CREATE EXTENSION IF NOT EXISTS "uuid-ossp"'
-
- create_table :project_files do
- primary_key :id, 'uuid', null: false, default: Hanami::Model::Sql.function(:uuid_generate_v4)
- column :name, String
- end
- end
-
- down do
- drop_table :project_files
- execute 'DROP EXTENSION IF EXISTS "uuid-ossp"'
- end
-end
-```
-
-```ruby
-ProjectFileRepository.new.create(name: "source.rb")
- # => #"239f8e0f-d764-4a76-aaa7-7b59b5301c72", :name=>"source.rb"}>
-```
-
-## Array
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :articles do
- primary_key :id
- column :title, String
- column :tags, "text[]"
- end
- end
-end
-```
-
-```ruby
-ArticleRepository.new.create(title: "Announcing Hanami 1.0", tags: ["announcements"])
- # => #1, :title=>"Announcing Hanami 1.0", :tags=>["announcements"]}>
-```
-
-## JSON(B)
-
-```ruby
-Hanami::Model.migration do
- change do
- create_table :commits do
- primary_key :id
- column :metadata, "jsonb"
- end
- end
-end
-```
-
-```ruby
-CommitRepository.new.create(metadata: { sha: "8775b81" })
- # => #1, :metadata=>{:sha=>"8775b81"}}>
-```
diff --git a/source/guides/1.1/repositories/sql-queries.md b/source/guides/1.1/repositories/sql-queries.md
deleted file mode 100644
index bae06ff1a..000000000
--- a/source/guides/1.1/repositories/sql-queries.md
+++ /dev/null
@@ -1,151 +0,0 @@
----
-title: "Guides - Repositories: SQL Queries"
-version: 1.1
----
-
-## Select
-
-You can select a subset of columns to be fetched from the database:
-
-```ruby
-class UserRepository < Hanami::Repository
- def all_with_name
- users.select(:id, :name)
- end
-end
-```
-
-## Sort
-
-You can sort records using `#order`:
-
-```ruby
-class UserRepository < Hanami::Repository
- def from_first_to_last
- users.order { created_at.asc }
- end
-
- def from_last_to_first
- users.order { created_at.desc }
- end
-
- def alphabetical
- users.order { name.asc }
- end
-
- def alphabetical_reverse
- users.order { name.asc }
- end
-
- def sort_via_other_relation
- users.order(books[:title].qualified.asc)
- end
-end
-```
-
-## Limit
-
-You can use `#limit` to limit the number of records fetched from the database:
-
-```ruby
-class UserRepository < Hanami::Repository
- def last_created(number)
- users.order { created_at.desc }.limit(number)
- end
-end
-```
-
-## SQL Functions
-
-You can use any SQL functions like `ILIKE`, `IN`, `NOT`, `LENGTH`, etc..
-These functions are available as Ruby methods inside the `#where` block:
-
-```ruby
-class UserRepository < Hanami::Repository
- def by_name(name)
- users.where { name.ilike("%?%", name) }
- end
-
- def by_id_in(input)
- users.where { id.in(input) }
- end
-
- def by_id_in_range(range)
- users.where { id.in(range) }
- end
-
- def by_id_min_max(min, max)
- users.where { id > min || id < max }
- end
-
- def by_not_id(input)
- users.where { id.not(input) }
- end
-
- def by_id_not_in_range(range)
- users.where { id.not(1..100) }
- end
-
- def by_name_length(input)
- users.where { length(:name) > input }
- end
-end
-```
-
-## Joins
-
-You can join several relations:
-
-```ruby
-class BookRepository < Hanami::Repository
- associations do
- has_many :comments
- end
-
- def commented_within(date_range)
- books
- .join(comments)
- .where(comments[:created_at].qualified => date_range)
- .as(Book)
- end
-end
-```
-
-
-For a given relation named :books
, the used foreign key in :comments
is :book_id
. That is the singular name of the relation with \_id
appended to it.
-
-
-In case your database schema doesn't follow this convention above, you can specify an explicit _foreign key_:
-
-```ruby
-class BookRepository < Hanami::Repository
- associations do
- has_many :comments
- end
-
- def commented_within(date_range)
- books
- .join(comments, id: :book_fk_id)
- .where(comments[:created_at].qualified => date_range)
- .as(Book).to_a
- end
-end
-```
-
-You can also use `#inner_join` method.
-
-## Group by
-
-```ruby
-class UserRepository < Hanami::Repository
- associations do
- has_many :books
- end
-
- def users_group_by_id
- users.
- left_join(:books).
- group(:id)
- end
-end
-```
diff --git a/source/guides/1.1/routing/basic-usage.md b/source/guides/1.1/routing/basic-usage.md
deleted file mode 100644
index 9fbbb0c81..000000000
--- a/source/guides/1.1/routing/basic-usage.md
+++ /dev/null
@@ -1,143 +0,0 @@
----
-title: Guides - Basic Usage
-version: 1.1
----
-
-# Basic Usage
-
-## Path matching
-
-In [our initial example](/guides/1.1/routing/overview) we have introduced a really basic relative URI: `/hello`.
-This is what we call _fixed path matching_.
-It is called this because the segment is responsible for responding only to an **exact match**.
-If we visit `/hello`, we get a response.
-If we hit `/foo`, a `404` (Not Found) is returned.
-
-### Fixed Matching
-
-```ruby
-# apps/web/config/routes.rb
-get '/dashboard', to: "dashboard#index"
-```
-
-### Variables
-
-When we have dynamic content to serve, we want our URI to be dynamic as well.
-This can be easily achieved via path variables.
-They are defined with a colon, followed by a name (eg. `:id`).
-
-Once an incoming request is forwarded to our endpoint, we can access the current value in our param's action (`params[:id]`).
-
-```ruby
-get '/books/:id', to: 'books#show'
-```
-
-Multiple variables can be used in a path.
-
-```ruby
-get '/books/:book_id/reviews/:id', to: 'reviews#show'
-```
-
-### Variables Constraints
-
-It's possible to specify constraints for each variable.
-The rule MUST be expressed as a regular expression.
-If a request can satisfy all of them, we're good, otherwise a `404` is returned.
-
-```ruby
-get '/authors/:id', id: /\d+/, to: 'authors#show'
-```
-
-### Optional Tokens
-
-Sometimes we want to specify an optional token as part of our URI.
-It should be expressed between round parentheses.
-If present, it will be available as param in the Rack env, otherwise it will be missing, but the endpoint will be still hit.
-
-```ruby
-get '/books(.:format)', to: 'books#show'
-```
-
-### Wildcard Matching
-
-Imagine we want to serve static files from a user repository.
-It would be impossible to know in advance which files are stored and to prepare routes accordingly.
-
-To solve this problem, Hanami supports _wildcard matching_.
-
-```ruby
-get '/files/*', to: 'files#show'
-```
-
-## Named Routes
-
-We can specify a unique name for each route, in order to generate paths from the router or to test them.
-
-```ruby
-root to: 'home#index'
-get '/hello', to: 'greet#index', as: :greeting
-get '/books/:id', to: 'books#show', as: :book
-```
-
-When a Hanami application starts, it generates a Ruby module at the runtime under our application namespace: eg. `Web.routes`.
-We can use it to generate a relative or absolute URI for our route.
-
-```ruby
-Web.routes.path(:root) # => "/"
-Web.routes.url(:root) # => "http://localhost:2300/"
-
-Web.routes.path(:greeting) # => "/hello"
-Web.routes.url(:greeting) # => "http://localhost:2300/hello"
-```
-
-When we have one or more variables, they can be specified as a Hash.
-
-```ruby
-Web.routes.path(:book, id: 1) # => "/books/1"
-Web.routes.url(:book, id: 1) # => "http://localhost:2300/books/1"
-```
-
-Absolute URL generation is dependent on `scheme`, `host` and `port` settings in `apps/web/application.rb`.
-
-### Routing Helpers
-
-Generating routes from `Web.routes` is helpful, because that module can be accessed from anywhere.
-However, this syntax is noisy.
-
-Hanami has _routing helpers_ available as `routes` in: **actions**, **views** and **templates**.
-
-```ruby
-<%= routes.path(:greeting) %>
-<%= routes.url(:greeting) %>
-```
-
-Or
-
-```ruby
-<%= routes.greeting_path %>
-<%= routes.greeting_url %>
-```
-
-## Namespaces
-
-If we want to group a set of resources under a common prefix we can use `namespace`.
-
-```ruby
-namespace 'docs' do
- get '/installation', to: 'docs#installation'
- get '/usage', to: 'docs#usage'
-end
-
-# This will generate:
-#
-# /docs/installation
-# /docs/usage
-```
-
-## Redirects
-
-In case of legacy routes, we can handle HTTP redirects at the routing level.
-
-```ruby
-redirect '/old', to: '/new'
-```
diff --git a/source/guides/1.1/routing/overview.md b/source/guides/1.1/routing/overview.md
deleted file mode 100644
index 731a6e731..000000000
--- a/source/guides/1.1/routing/overview.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: Guides - Routing Overview
-version: 1.1
----
-
-# Overview
-
-Hanami applications use [Hanami::Router](https://github.com/hanami/router) for routing: a Rack compatible, lightweight and fast HTTP router for Ruby.
-
-## Getting started
-
-With your favorite editor open `apps/web/config/routes.rb` and add the following line.
-
-```ruby
-get '/hello', to: ->(env) { [200, {}, ['Hello from Hanami!']] }
-```
-
-Then start the server with `bundle exec hanami server` and visit [http://localhost:2300/hello](http://localhost:2300/hello).
-You should see `Hello from Hanami!` in your browser.
-
-Let's explain what we just did.
-We created a **route**; an application can have many routes.
-Each route starts with an [HTTP verb](http://www.w3.org/Protocols/rfc2616/rfc2616-sec9.html) declaration, `get` in our case.
-Then we specify a relative URI (`/hello` for us) and the object that is responsible to respond to incoming requests.
-
-We can use most common HTTP verbs: `GET`, `POST`, `PUT`, `PATCH`, `DELETE`, `TRACE` and `OPTIONS`.
-
-```ruby
-endpoint = ->(env) { [200, {}, ['Hello from Hanami!']] }
-
-get '/hello', to: endpoint
-post '/hello', to: endpoint
-put '/hello', to: endpoint
-patch '/hello', to: endpoint
-delete '/hello', to: endpoint
-trace '/hello', to: endpoint
-options '/hello', to: endpoint
-```
-
-## Rack
-
-Hanami is compatible with [Rack SPEC](http://www.rubydoc.info/github/rack/rack/master/file/SPEC), and so the endpoints that we use MUST be compliant as well.
-In the example above we used a `Proc` that was fitting our requirements.
-
-A valid endpoint can be an object, a class, an action, or an **application** that responds to `#call`.
-
-```ruby
-get '/proc', to: ->(env) { [200, {}, ['Hello from Hanami!']] }
-get '/action', to: "home#index"
-get '/middleware', to: Middleware
-get '/rack-app', to: RackApp.new
-get '/rails', to: ActionControllerSubclass.action(:new)
-```
-
-When we use a string, it tries to instantiate a class from it:
-
-```ruby
-get '/rack-app', to: 'rack_app' # it will map to RackApp.new
-```
-
-## Actions
-
-Full Rack integration is great, but the most common endpoint that we'll use in our web applications is an **action**.
-Actions are objects responsible for responding to incoming HTTP requests.
-They have a nested naming like `Web::Controllers::Home::Index`.
-This is a really long name to write, that's why Hanami has a **naming convention** for it: `"home#index"`.
-
-```ruby
-# apps/web/config/routes.rb
-root to: "home#index" # => will route to Web::Controllers::Home::Index
-```
-
-The first token is the name of the controller `"home"` is translated to `Home`.
-The same transformation will be applied to the name after the `#`: `"index"` to `Index`.
-
-Hanami is able to figure out the namespace (`Web::Controllers`) and compose the full class name.
-
-### Mounting Applications
-
-If we want to mount an application, we should use `mount` within the Hanami environment configuration file. The global configuration file is located at `config/environment.rb`. Place `mount` within the Hanami.configure block.
-
-```ruby
-Hanami.configure do
- mount Web::Application, at: '/'
- mount OtherApplication.new, at: '/other'
-
- ...
-end
-```
-
-#### Mounting To A Path
-
-```ruby
-mount SinatraApp.new, at: '/sinatra'
-```
-
-All the HTTP requests starting with `/sinatra` will be routed to `SinatraApp`.
-
-#### Mounting On A Subdomain
-
-```ruby
-mount Blog.new, host: 'blog'
-```
-
-All the HTTP requests to `http://blog.example.com` will be routed to `Blog`.
-
-
- In development, you will NOT be able to access http://blog.localhost:2300
,
- so you should specify a host when running the server:
- bundle exec hanami server --host=lvh.me
.
- Then your application can be visited at http://blog.lvh.me:2300
-
diff --git a/source/guides/1.1/routing/restful-resources.md b/source/guides/1.1/routing/restful-resources.md
deleted file mode 100644
index 575dca22f..000000000
--- a/source/guides/1.1/routing/restful-resources.md
+++ /dev/null
@@ -1,483 +0,0 @@
----
-title: Guides - RESTful Resource(s)
-version: 1.1
----
-
-# REST
-
-Hanami has native [REST](http://en.wikipedia.org/wiki/Representational_state_transfer) support.
-
-At the routing level, there are two methods that can be used to declare them: `resources` and `resource`.
-The former is for plural resources, the latter for singular ones.
-
-Declaring a resource means to generate **several default routes** with just one line of code.
-
-## RESTful Resources
-
-### Default Routes
-
-```ruby
-# apps/web/config/routes.rb
-resources :books
-```
-
-It generates
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /books
- Books::Index
- :index
- :books
-
-
- GET
- /books/:id
- Books::Show
- :show
- :book
-
-
- GET
- /books/new
- Books::New
- :new
- :new_book
-
-
- POST
- /books
- Books::Create
- :create
- :books
-
-
- GET
- /books/:id/edit
- Books::Edit
- :edit
- :edit_book
-
-
- PATCH
- /books/:id
- Books::Update
- :update
- :book
-
-
- DELETE
- /books/:id
- Books::Destroy
- :destroy
- :book
-
-
-
-### Remove Routes
-
-In case we don't need all the default routes we can use `:only` and pass one or more action names.
-We can also black list routes with `:except`.
-
-```ruby
-resources :books, only: [:new, :create, :show]
-
-# equivalent to
-
-resources :books, except: [:index, :edit, :update, :destroy]
-```
-
-### Add Routes
-
-Alongside with default routes we can specify extra routes for single (`member`) or multiple (`collection`) resources.
-
-```ruby
-resources :books do
- member do
- # Generates /books/1/toggle, maps to Books::Toggle, named :toggle_book
- get 'toggle'
- end
-
- collection do
- # Generates /books/search, maps to Books::Search, named :search_books
- get 'search'
- end
-end
-```
-
-### Configure Controller
-
-Imagine we have a controller named `manuscripts`, where we have actions like `Manuscripts::Index`, but we still want to expose those resources as `/books`.
-Using the `:controller` option will save our day.
-
-```ruby
-resources :books, controller: 'manuscripts'
-
-# GET /books/1 will route to Manuscripts::Show, etc.
-```
-
-## RESTful Resource
-
-```ruby
-resource :account
-```
-
-It generates
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /account
- Account::Show
- :show
- :account
-
-
- GET
- /account/new
- Account::New
- :new
- :new_account
-
-
- POST
- /account
- Account::Create
- :create
- :account
-
-
- GET
- /account/edit
- Account::Edit
- :edit
- :edit_account
-
-
- PATCH
- /account
- Account::Update
- :update
- :account
-
-
- DELETE
- /account
- Account::Destroy
- :destroy
- :account
-
-
-
-### Remove Routes
-
-```ruby
-resource :account, only: [:show, :edit, :update, :destroy]
-
-# equivalent to
-
-resource :account, except: [:new, :create]
-```
-
-### Add Routes
-
-```ruby
-resource :account do
- member do
- # Generates /account/avatar, maps to Account::Avatar, named :avatar_account
- get 'avatar'
- end
-
- collection do
- # Generates /account/authorizations, maps to Account::Authorizations, named :authorizations_account
- get 'authorizations'
- end
-end
-```
-
-### Configure Controller
-
-```ruby
-resource :account, controller: 'customer'
-```
-
-## Nested Resource(s)
-
-RESTful resource(s) can be nested in order to make available inner resources inside the scope of their parents.
-
-### Plural to plural
-
-```ruby
-resources :books do
- resources :reviews
-end
-```
-
-**It generates default routes for books and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /books/:book_id/reviews
- Books::Reviews::Index
- :index
- :book_reviews
-
-
- GET
- /books/:book_id/reviews/:id
- Books::Reviews::Show
- :show
- :book_review
-
-
- GET
- /books/:book_id/reviews/new
- Books::Reviews::New
- :new
- :new_book_review
-
-
- POST
- /books/:book_id/reviews
- Books::Reviews::Create
- :create
- :book_reviews
-
-
- GET
- /books/:book_id/reviews/:id/edit
- Books::Reviews::Edit
- :edit
- :edit_book_review
-
-
- PATCH
- /books/:book_id/reviews/:id
- Books::Reviews::Update
- :update
- :book_review
-
-
- DELETE
- /books/:book_id/reviews/:id
- Books::Reviews::Destroy
- :destroy
- :book_review
-
-
-
-### Plural to singular
-
-```ruby
-resources :books do
- resource :cover
-end
-```
-
-**It generates default routes for books and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /books/:book_id/cover
- Books::Cover::Show
- :show
- :book_cover
-
-
- GET
- /books/:book_id/cover/new
- Books::Cover::New
- :new
- :new_book_cover
-
-
- POST
- /books/:book_id/cover
- Books::Cover::Create
- :create
- :book_cover
-
-
- GET
- /books/:book_id/cover/edit
- Books::Cover::Edit
- :edit
- :edit_book_cover
-
-
- PATCH
- /books/:book_id/cover
- Books::Cover::Update
- :update
- :book_cover
-
-
- DELETE
- /books/:book_id/cover
- Books::Cover::Destroy
- :destroy
- :book_cover
-
-
-
-### Singular To Plural
-
-```ruby
-resource :account do
- resources :api_keys
-end
-```
-
-**It generates default routes for account and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /account/api_keys
- Account::ApiKeys::Index
- :index
- :account_api_keys
-
-
- GET
- /account/api_keys/:id
- Account::ApiKeys::Show
- :show
- :account_api_key
-
-
- GET
- /account/api_keys/new
- Account::ApiKeys::New
- :new
- :new_account_api_key
-
-
- POST
- /account/api_keys
- Account::ApiKeys::Create
- :create
- :account_api_keys
-
-
- GET
- /account/api_keys/:id/edit
- Account::ApiKeys::Edit
- :edit
- :edit_account_api_key
-
-
- PATCH
- /account/api_keys/:id
- Account::ApiKeys::Update
- :update
- :account_api_key
-
-
- DELETE
- /account/api_keys/:id
- Account::ApiKeys::Destroy
- :destroy
- :account_api_key
-
-
-
-### Singular To Singular
-
-```ruby
-resource :account do
- resource :avatar
-end
-```
-
-**It generates default routes for account and the following ones.**
-
-
-
- Verb
- Path
- Action
- Name
- Named Route
-
-
- GET
- /account/avatar
- Account::Avatar::Show
- :show
- :account_avatar
-
-
- GET
- /account/avatar/new
- Account::Avatar::New
- :new
- :new_account_avatar
-
-
- POST
- /account/avatar
- Account::Avatar::Create
- :create
- :account_avatar
-
-
- GET
- /account/avatar/edit
- Account::Avatar::Edit
- :edit
- :edit_account_avatar
-
-
- PATCH
- /account/avatar
- Account::Avatar::Update
- :update
- :account_avatar
-
-
- DELETE
- /account/avatar
- Account::Avatar::Destroy
- :destroy
- :account_avatar
-
-
diff --git a/source/guides/1.1/routing/testing.md b/source/guides/1.1/routing/testing.md
deleted file mode 100644
index 654da2db9..000000000
--- a/source/guides/1.1/routing/testing.md
+++ /dev/null
@@ -1,75 +0,0 @@
----
-title: Guides - Routing Testing
-version: 1.1
----
-
-# Testing
-
-Hanami has builtin facilities for routing unit tests.
-
-## Path Generation
-
-We can assert the generated routes, to do so, we're gonna create a spec file for the purpose.
-`Web.routes` is the class that holds all the routes for the application named `Web`.
-
-It exposes a method to generate a path, which takes the [name of a route](/guides/1.1/routing/basic-usage#named-routes) as a symbol.
-Here's how to test it.
-
-```ruby
-# spec/web/routes_spec.rb
-RSpec.describe Web.routes do
- it 'generates "/"' do
- actual = described_class.path(:root)
- expect(actual).to eq '/'
- end
-
- it 'generates "/books/23"' do
- actual = described_class.path(:book, id: 23)
- expect(actual).to eq '/books/23'
- end
-end
-```
-
-## Route Recognition
-
-We can also do the opposite: starting from a fake Rack env, we can assert that the recognized route is correct.
-
-```ruby
-# spec/web/routes_spec.rb
-RSpec.describe Web.routes do
-
- # ...
-
- it 'recognizes "GET /"' do
- env = Rack::MockRequest.env_for('/')
- route = described_class.recognize(env)
-
- expect(route).to be_routable
-
- expect(route.path).to eq '/'
- expect(route.verb).to eq 'GET'
- expect(route.params).to eq({})
- end
-
- it 'recognizes "PATCH /books/23"' do
- env = Rack::MockRequest.env_for('/books/23', method: 'PATCH')
- route = described_class.recognize(env)
-
- expect(route).to be_routable
-
- expect(route.path).to eq '/books/23'
- expect(route.verb).to eq 'PATCH'
- expect(route.params).to eq(id: '23')
- end
-
- it 'does not recognize unknown route' do
- env = Rack::MockRequest.env_for('/foo')
- route = subject.recognize(env)
-
- expect(route).to_not be_routable
- end
-end
-```
-
-When we use `.recognize`, the router returns a recognized route, which is an object designed only for testing purposes.
-It carries on all the important information about the route that we have hit.
diff --git a/source/guides/1.1/upgrade-notes/v060.md b/source/guides/1.1/upgrade-notes/v060.md
deleted file mode 100644
index 75f77b7f7..000000000
--- a/source/guides/1.1/upgrade-notes/v060.md
+++ /dev/null
@@ -1,62 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.6.0
-version: 1.1
----
-
-## Upgrade Notes for v0.6.0
-
- * Add `SERVE_STATIC_ASSETS="true"` to `.env.development` and `.env.test` in order to serve static assets locally.
-
- * Add `require 'hanami/rake_tasks'` to `Rakefile` in order to enable `:preload` and `:environment` Rake tasks
-
- * Rename `default_format` into `default_request_format` for all the applications (eg. `apps/web/application.rb`)
-
- * Delete all `serve_assets` occurrences from all the applications (eg. `apps/web/application.rb`)
-
- * Create `public/` directory at the root of the project (if not already existing)
-
- * Add `public/assets*` to `.gitignore`
-
- * Rename `apps/web/public` into `apps/web/assets` as assets sources
-
- * Add `require 'hanami/assets'` at the top of `apps/web/application.rb`
-
- * Add `include Web::Assets::Helpers` into `view.prepare` block of `apps/web/application.rb`
-
- * Change assets configuration into `apps/web/application.rb` from:
-
- ```ruby
- assets << [
- # 'vendor/javascripts'
- ]
- ```
-
- to:
-
- ```ruby
- assets do
- javascript_compressor :builtin
- stylesheet_compressor :builtin
-
- sources << [
- 'assets',
- # 'vendor/assets'
- ]
- end
- ```
-
- * Add the following code **inside** the `configure :production` block of `apps/web/application.rb`
-
- ```ruby
- assets do
- compile false
- digest true
-
- # CDN Mode (optional)
- # scheme 'https'
- # host '123.cloudfront.net'
- # port 443
- end
- ```
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.1/upgrade-notes/v070.md b/source/guides/1.1/upgrade-notes/v070.md
deleted file mode 100644
index ca90d33de..000000000
--- a/source/guides/1.1/upgrade-notes/v070.md
+++ /dev/null
@@ -1,20 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.7.0
-version: 1.1
----
-
-## Upgrade Notes for v0.7.0
-
- * Rename all the gems in your `Gemfile` from `lotus` to `hanami`
-
- * Rename `.lotusrc` into `.hanamirc`
-
- * Find and replace in project: `lotus` => `hanami`
-
- * Find and replace in project: `Lotus` => `Hanami`
-
- * Find and replace in project: `LOTUS` => `HANAMI`
-
- * Rename the environment variable on your server from `LOTUS_ENV` to `HANAMI_ENV`
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.1/upgrade-notes/v080.md b/source/guides/1.1/upgrade-notes/v080.md
deleted file mode 100644
index 710f410b3..000000000
--- a/source/guides/1.1/upgrade-notes/v080.md
+++ /dev/null
@@ -1,42 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.8.0
-version: 1.1
----
-
-## Upgrade Notes for v0.8.0
-
- * Use Ruby 2.2+
-
- * Edit your `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 0.8'`.
-
- * Create a group `:development` in `Gemfile` and add `gem 'shotgun'`
-
- * Create a group `:development, :test` in `Gemfile` and add `gem 'dotenv', '~> 2.0'`
-
- * Edit `.hanamirc` by adding a new key `project`. The value must be the snake_case name of the project. Eg. project=active\_citizens
.
-
- * Edit `.env.*` files and change env variables from `_DATABASE_URL` to `DATABASE_URL`.
-
- * Edit `lib/.rb` and change the `adapter -> uri:` variable from `ENV['_DATABASE_URL']` to `ENV['DATABASE_URL']`
-
- * Change params validation syntax. Learn more at [Hanami::Validations README](https://github.com/hanami/validations#usage).
-
- * Change params access syntax to symbols. Eg `params['book']` is no longer supported.
-
- * The returning value of `params.errors` has changed: now it's a Hash with key the attribute name and value an array of strings with error messages.
-
- * In views, layouts and templates use `#local` instead of `#content`, which is now deprecated.
-
- * [Optional] Edit [logging settings](/guides/1.1/projects/logging) in `apps/web/application.rb`.
-
- * [Optional] Add `security.x_content_type_options 'nosniff'` to `apps/web/application.rb`.
-
- * [Optional] Add `security.x_xss_protection '1; mode=block'` to `apps/web/application.rb`.
-
- * [Optional] Add `subresource_integrity :sha256` to `assets` block in `configure :production` to `apps/web/application.rb`.
-
- * [Optional] Minitest users can disable Rake 11 warnings by adding `t.warning = false` to the `Rake::TestTask.new do |t|` block in `Rakefile`
-
- * [Optional] RSpec users can disable Rake 11 warnings by adding `config.warnings = false ` to the `RSpec.configure |config|` block in spec/spec\_helper.rb
.
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.1/upgrade-notes/v090.md b/source/guides/1.1/upgrade-notes/v090.md
deleted file mode 100644
index d58f3a232..000000000
--- a/source/guides/1.1/upgrade-notes/v090.md
+++ /dev/null
@@ -1,95 +0,0 @@
----
-title: Guides - Upgrade Notes for v0.9.0
-version: 1.1
----
-
-## Upgrade Notes for v0.9.0
-
- * Use Ruby 2.3+
-
- * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 0.9'`
-
- * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 0.7'`
-
- * Edit `config/environment.rb` as shown below
-
- * Edit `lib/bookshelf.rb` as shown below
-
- * Edit `spec/spec_helper.rb`, by replacing `Hanami::Application.preload!` with `Hanami.boot`
-
- * Edit `spec/spec_helper.rb`, by adding `Hanami::Utils.require!("spec/support")` (optional)
-
- * Edit `spec/features_helper.rb`, by replacing `Capybara.app = Hanami::Container.new` with `Capybara.app = Hanami.app`
-
- * Edit `config.ru`, by replacing `run Hanami::Container.new` with `run Hanami.app`
-
- * Edit each single application configuration (eg `apps/web/application.rb`) by replacing `digest` with `fingerprint` in `assets` block(s)
-
- * Remove custom subclasses of `Hanami::Model::Coercer` (if any), as PostgreSQL types are now natively supported
-
- * Edit all the repositories (`lib/bookshelf/repositories`) to inherit from `Hanami::Repository` instead of including it
-
- * Edit all the entities (`lib/bookshelf/entities`) to inherit from `Hanami::Entity` instead of including it
-
- * Edit all the repositories by moving the class level methods to instance level
-
- * Update all the repositories with the [new syntax](/guides/1.1/models/repositories)
-
- * Edit all the entities by removing `.attributes`
-
-### `config/environment.rb`
-
-```ruby
-require 'bundler/setup'
-require 'hanami/setup'
-require 'hanami/model' # Add this line
-require_relative '../lib/bookshelf'
-require_relative '../apps/web/application'
-
-# This used to be `Hanami::Container.configure`, now it must be `Hanami.configure`
-Hanami.configure do
- mount Web::Application, at: '/'
-
- # This is a new block
- #
- # Cut and paste the contents of `Hanami::Model.configure` from lib/bookshelf.rb
- model do
-
- # This used to be:
- #
- # adapter type: :sql, url: ENV['DATABASE_URL']
- adapter :sql, ENV['DATABASE_URL']
-
- migrations 'db/migrations'
- schema 'db/schema.sql'
-
- #
- # Mapping block isn't supported anymore
- #
- end
-
- # This is a new block
- #
- # Cut and paste the contents of `Hanami::Mailer.configure` from lib/bookshelf.rb
- mailer do
-
- # Adjust the new layer `root` location
- root Hanami.root.join("lib", "bookshelf", "mailers")
-
- delivery do
- development :test
- test :test
- # production :smtp, address: ENV['SMTP_PORT'], port: 1025
- end
- end
-end
-```
-
-### `lib/bookshelf.rb`
-
-```ruby
-# This line is enough ;)
-Hanami::Utils.require!("lib/bookshelf")
-```
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.1/upgrade-notes/v100.md b/source/guides/1.1/upgrade-notes/v100.md
deleted file mode 100644
index 32944a9f9..000000000
--- a/source/guides/1.1/upgrade-notes/v100.md
+++ /dev/null
@@ -1,85 +0,0 @@
----
-title: Guides - Upgrade Notes for v1.0.0
-version: 1.1
----
-
-## Upgrade Notes for v1.0.0
-
- * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 1.0'`
-
- * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 1.0'`
-
- * Edit `Gemfile`, by removing Bundler: `gem 'bundler'` can be deleted
-
- * Add `config/boot.rb` as shown below
-
- * Edit `config/environment.rb` as shown below
-
- * Edit `lib/bookshelf.rb` as shown below
-
- * Edit all the applications to remove the `logger` settings. Eg. `apps/web/application.rb`
-
- * Edit the project using `Hanami.logger` instead of application level loggers. Eg. `Web.logger`
-
-
-### `config/boot.rb`
-
-```ruby
-require_relative './environment'
-Hanami.boot
-```
-
-This file can be used to boot your project from external commands. For instance to use it with Sidekiq.
-
-### `config/environment.rb`
-
-```ruby
-require 'bundler/setup'
-require 'hanami/setup'
-require 'hanami/model'
-require_relative '../lib/bookshelf'
-require_relative '../apps/web/application'
-
-Hanami.configure do
- mount Web::Application, at: '/'
-
- model do
- adapter :sql, ENV['DATABASE_URL']
-
- migrations 'db/migrations'
- schema 'db/schema.sql'
- end
-
- mailer do
- # Make sure this folder exists, or delete this row.
- root Hanami.root.join("lib", "bookshelf", "mailers")
-
- # This has changed. It used to be a block, now it's a setting
- delivery :test
- end
-
-Β Β # These two blocks are new.
- # They MUST be after the general settings like `mount`, `model`, `mailer`.
- environment :development do
- # See: http://hanamirb.org/guides/1.1/projects/logging
- logger level: :info
- end
-
- environment :production do
- logger level: :info, formatter: :json
-
- mailer do
- delivery :smtp, address: ENV['SMTP_HOST'], port: ENV['SMTP_PORT']
- end
- end
-end
-```
-
-### `lib/bookshelf.rb`
-
-```ruby
-module Bookshelf
-end
-```
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.1/upgrade-notes/v110.md b/source/guides/1.1/upgrade-notes/v110.md
deleted file mode 100644
index 5c902f9bd..000000000
--- a/source/guides/1.1/upgrade-notes/v110.md
+++ /dev/null
@@ -1,14 +0,0 @@
----
-title: Guides - Upgrade Notes for v1.1.0
-version: 1.1
----
-
-## Upgrade Notes for v1.1.0
-
- * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 1.1'`
-
- * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 1.1'`
-
- * Run `bundle update hanami hanami-model`
-
-**If you have any problem, don't hesitate to look for help in [chat](http://chat.hanamirb.org).**
diff --git a/source/guides/1.1/validations/advanced-usage.md b/source/guides/1.1/validations/advanced-usage.md
deleted file mode 100644
index 0ce11b1aa..000000000
--- a/source/guides/1.1/validations/advanced-usage.md
+++ /dev/null
@@ -1,461 +0,0 @@
----
-title: Guides - Advanced Usage
-version: 1.1
----
-
-# Advanced Usage
-
-### Required and Optional keys
-
-HTML forms can have required or optional fields. We can express this concept with two methods in our validations: `required` (which we already met in previous examples), and `optional`.
-
-```ruby
-require 'hanami/validations'
-
-class Signup
- include Hanami::Validations
-
- validations do
- required(:email) { ... }
- optional(:referral) { ... }
- end
-end
-```
-
-### Type Safety
-
-At this point, we need to explicitly tell something really important about built-in predicates. Each of them have expectations about the methods that an input is able to respond to.
-
-Why this is so important? Because if we try to invoke a method on the input weβll get a `NoMethodError` if the input doesnβt respond to it. Which isnβt nice, right?
-
-Before to use a predicate, we want to ensure that the input is an instance of the expected type. Letβs introduce another new predicate for our need: `#type?`.
-
-```ruby
-required(:age) { type?(Integer) & gteq?(18) }
-```
-
-It takes the input and tries to coerce it. If it fails, the execution stops. If it succeed, the subsequent predicates can trust `#type?` and be sure that the input is an integer.
-
-**We suggest to use `#type?` at the beginning of the validations block. This _type safety_ policy is crucial to prevent runtime errors.**
-
-`Hanami::Validations` supports the most common Ruby types:
-
- * `Array` (aliased as `array?`)
- * `BigDecimal` (aliased as `decimal?`)
- * `Boolean` (aliased as `bool?`)
- * `Date` (aliased as `date?`)
- * `DateTime` (aliased as `date_time?`)
- * `Float` (aliased as `float?`)
- * `Hash` (aliased as `hash?`)
- * `Integer` (aliased as `int?`)
- * `String` (aliased as `str?`)
- * `Time` (aliased as `time?`)
-
-For each supported type, there a convenient predicate that acts as an alias. For instance, the two lines of code below are **equivalent**.
-
-```ruby
-required(:age) { type?(Integer) }
-required(:age) { int? }
-```
-
-### Macros
-
-Rule composition with blocks is powerful, but it can become verbose.
-To reduce verbosity, `Hanami::Validations` offers convenient _macros_ that are internally _expanded_ (aka interpreted) to an equivalent _block expression_
-
-#### Filled
-
-To use when we expect a value to be filled:
-
-```ruby
-# expands to
-# required(:age) { filled? }
-
-required(:age).filled
-```
-
-```ruby
-# expands to
-# required(:age) { filled? & type?(Integer) }
-
-required(:age).filled(:int?)
-```
-
-```ruby
-# expands to
-# required(:age) { filled? & type?(Integer) & gt?(18) }
-
-required(:age).filled(:int?, gt?: 18)
-```
-
-In the examples above `age` is **always required** as value.
-
-#### Maybe
-
-To use when a value can be nil:
-
-```ruby
-# expands to
-# required(:age) { none? | int? }
-
-required(:age).maybe(:int?)
-```
-
-In the example above `age` can be `nil`, but if we send the value, it **must** be an integer.
-
-#### Each
-
-To use when we want to apply the same validation rules to all the elements of an array:
-
-```ruby
-# expands to
-# required(:tags) { array? { each { str? } } }
-
-required(:tags).each(:str?)
-```
-
-In the example above `tags` **must** be an array of strings.
-
-
-#### Confirmation
-
-This is designed to check if pairs of web form fields have the same value. One wildly popular example is _password confirmation_.
-
-```ruby
-required(:password).filled.confirmation
-```
-
-It is valid if the input has `password` and `password_confirmation` keys with the same exact value.
-
-β **CONVENTION:** For a given key `password`, the _confirmation_ predicate expects another key `password_confirmation`. Easy to tell, itβs the concatenation of the original key with the `_confirmation` suffix. Their values must be equal. β
-
-### Forms
-
-An important precondition to check before to implement a validator is about the expected input.
-When we use validators for already preprocessed data it's safe to use basic validations from `Hanami::Validations` mixin.
-
-If the data is coming directly from user input via a HTTP form, it's advisable to use `Hanami::Validations::Form` instead.
-**The two mixins have the same API, but the latter is able to do low level input preprocessing specific for forms**. For instance, blank inputs are casted to `nil` in order to avoid blank strings in the database.
-
-### Rules
-
-Predicates and macros are tools to code validations that concern a single key like `first_name` or `email`.
-If the outcome of a validation depends on two or more attributes we can use _rules_.
-
-Here's a practical example: a job board.
-We want to validate the form of the job creation with some mandatory fields: `type` (full time, part-time, contract), `title` (eg. Developer), `description`, `company` (just the name) and a `website` (which is optional).
-An user must specify the location: on-site or remote. If it's on site, they must specify the `location`, otherwise they have to tick the checkbox for `remote`.
-
-Here's the code:
-
-```ruby
-class CreateJob
- include Hanami::Validations::Form
-
- validations do
- required(:type).filled(:int?, included_in?: [1, 2, 3])
-
- optional(:location).maybe(:str?)
- optional(:remote).maybe(:bool?)
-
- required(:title).filled(:str?)
- required(:description).filled(:str?)
- required(:company).filled(:str?)
-
- optional(:website).filled(:str?, format?: URI.regexp(%w(http https)))
-
- rule(location_presence: [:location, :remote]) do |location, remote|
- (remote.none? | remote.false?).then(location.filled?) &
- remote.true?.then(location.none?)
- end
- end
-end
-```
-
-We specify a rule with `rule` method, which takes an arbitrary name and an array of preconditions.
-Only if `:location` and `:remote` are valid according to their validations described above, the `rule` block is evaluated.
-
-The block yields the same exact keys that we put in the precondintions.
-So for `[:location, :remote]` it will yield the corresponding values, bound to the `location` and `remote` variables.
-
-We can use these variables to define the rule. We covered a few cases:
-
- * If `remote` is missing or false, then `location` must be filled
- * If `remote` is true, then `location` must be omitted
-
-### Nested Input Data
-
-While weβre building complex web forms, we may find comfortable to organise data in a hierarchy of cohesive input fields. For instance, all the fields related to a customer, may have the `customer` prefix. To reflect this arrangement on the server side, we can group keys.
-
-```ruby
-validations do
- required(:customer).schema do
- required(:email) { β¦ }
- required(:name) { β¦ }
- # other validations β¦
- end
-end
-```
-
-Groups can be **deeply nested**, without any limitation.
-
-```ruby
-validations do
- required(:customer).schema do
- # other validations β¦
-
- required(:address).schema do
- required(:street) { β¦ }
- # other address validations β¦
- end
- end
-end
-```
-
-### Composition
-
-Until now, we have seen only small snippets to show specific features. That really close view prevents us to see the big picture of complex real world projects.
-
-As the code base grows, itβs a good practice to DRY validation rules.
-
-```ruby
-class AddressValidator
- include Hanami::Validations
-
- validations do
- required(:street) { β¦ }
- end
-end
-```
-
-This validator can be reused by other validators.
-
-```ruby
-class CustomerValidator
- include Hanami::Validations
-
- validations do
- required(:email) { β¦ }
- required(:address).schema(AddressValidator)
- end
-end
-```
-
-Again, there is no limit to the nesting levels.
-
-```ruby
-class OrderValidator
- include Hanami::Validations
-
- validations do
- required(:number) { β¦ }
- required(:customer).schema(CustomerValidator)
- end
-end
-```
-
-In the end, `OrderValidator` is able to validate a complex data structure like this:
-
-```ruby
-{
- number: "123",
- customer: {
- email: "user@example.com",
- address: {
- city: "Rome"
- }
- }
-}
-```
-
-### Whitelisting
-
-Another fundamental role that validators plays in the architecture of our projects is input whitelisting.
-For security reasons, we want to allow known keys to come in and reject everything else.
-
-This process happens when we invoke `#validate`.
-Allowed keys are the ones defined with `.required`.
-
-**Please note that whitelisting is only available for `Hanami::Validations::Form` mixin.**
-
-### Result
-
-When we trigger the validation process with `#validate`, we get a result object in return. Itβs able to tell if itβs successful, which rules the input data has violated and an output data bag.
-
-```ruby
-result = OrderValidator.new({}).validate
-result.success? # => false
-```
-
-#### Messages
-
-`result.messages` returns a nested set of validation error messages.
-
-Each error carries on informations about a single rule violation.
-
-```ruby
-result.messages.fetch(:number) # => ["is missing"]
-result.messages.fetch(:customer) # => ["is missing"]
-```
-
-#### Output
-
-`result.output` is a `Hash` which is the result of whitelisting and coercions. Itβs useful to pass it do other components that may want to persist that data.
-
-```ruby
-{
- "number" => "123",
- "unknown" => "foo"
-}
-```
-
-If we receive the input above, `output` will look like this.
-
-```ruby
-result.output
- # => { :number => 123 }
-```
-
-We can observe that:
-
- * Keys are _symbolized_
- * Only whitelisted keys are included
- * Data is coerced
-
-### Error Messages
-
-To pick the right error message is crucial for user experience.
-As usual `Hanami::Validations` comes to the rescue for most common cases and it leaves space to customization of behaviors.
-
-We have seen that builtin predicates have default messages, while [inline predicates](#inline-custom-predicates) allow to specify a custom message via the `:message` option.
-
-```ruby
-class SignupValidator
- include Hanami::Validations
-
- predicate :email?, message: 'must be an email' do |current|
- # ...
- end
-
- validations do
- required(:email).filled(:str?, :email?)
- required(:age).filled(:int?, gt?: 18)
- end
-end
-
-result = SignupValidator.new(email: 'foo', age: 1).validate
-
-result.success? # => false
-result.messages.fetch(:email) # => ['must be an email']
-result.messages.fetch(:age) # => ['must be greater than 18']
-```
-
-#### Configurable Error Messages
-
-Inline error messages are ideal for quick and dirty development, but we suggest to use an external YAML file to configure these messages:
-
-```yaml
-# config/messages.yml
-en:
- errors:
- email?: "must be an email"
-```
-
-To be used like this:
-
-```ruby
-class SignupValidator
- include Hanami::Validations
- messages_path 'config/messages.yml'
-
- predicate :email? do |current|
- # ...
- end
-
- validations do
- required(:email).filled(:str?, :email?)
- required(:age).filled(:int?, gt?: 18)
- end
-end
-
-```
-
-
-#### Custom Error Messages
-
-In the example above, the failure message for age is fine: `"must be greater than 18"`, but how to tweak it? What if we need to change into something diffent? Again, we can use the YAML configuration file for our purpose.
-
-```yaml
-# config/messages.yml
-en:
- errors:
- email?: "must be an email"
-
- rules:
- signup:
- age:
- gt?: "must be an adult"
-
-```
-
-Now our validator is able to look at the right error message.
-
-```ruby
-result = SignupValidator.new(email: 'foo', age: 1).validate
-
-result.success? # => false
-result.messages.fetch(:age) # => ['must be an adult']
-```
-
-##### Custom namespace
-
-β **CONVENTION:** For a given validator named `SignupValidator`, the framework will look for `signup` translation key. β
-
-If for some reason that doesn't work for us, we can customize the namespace:
-
-```ruby
-class SignupValidator
- include Hanami::Validations
-
- messages_path 'config/messages.yml'
- namespace :my_signup
-
- # ...
-end
-```
-
-The new namespace should be used in the YAML file too.
-
-```yaml
-# config/messages.yml
-en:
- # ...
- rules:
- my_signup:
- age:
- gt?: "must be an adult"
-
-```
-
-#### Internationalization (I18n)
-
-If your project already depends on `i18n` gem, `Hanami::Validations` is able to look at the translations defined for that gem and to use them.
-
-
-```ruby
-class SignupValidator
- include Hanami::Validations
-
- messages :i18n
-
- # ...
-end
-```
-
-```yaml
-# config/locales/en.yml
-en:
- errors:
- signup:
- # ...
-```
diff --git a/source/guides/1.1/validations/boolean-logic.md b/source/guides/1.1/validations/boolean-logic.md
deleted file mode 100644
index 55d42b743..000000000
--- a/source/guides/1.1/validations/boolean-logic.md
+++ /dev/null
@@ -1,192 +0,0 @@
----
-title: Guides - Boolean Logic
-version: 1.1
----
-
-# Boolean Logic
-
-When we check data, we expect only two outcomes: an input can be valid or not. No grey areas, nor fuzzy results. Itβs white or black, 1 or 0, `true` or `false` and _boolean logic_ is the perfect tool to express these two states. Indeed, a Ruby _boolean expression_ can only return `true` or `false`.
-
-To better recognise the pattern, letβs get back to the example above. This time we will map the natural language rules with programming language rules.
-
-```
-required(:name) { filled? & str? & size? (3..64) }
-```
-
-Now, I hope youβll never format code like that, but in this case, that formatting serves well our purpose to show how Rubyβs simplicity helps to define complex rules with no effort.
-
-From a high level perspective, we can tell that input data for `name` is _valid_ only if **all** the requirements are satisfied. Thatβs because we used `&`.
-
-#### Logic Operators
-
-We support four logic operators:
-
- * `&` (aliased as `and`) for _conjunction_
- * `|` (aliased as `or`) for _disjunction_
- * `>` (aliased as `then`) for _implication_
- * `^` (aliased as `xor`) for _exclusive disjunction_
-
-#### Context Of Execution
-
-**Please notice that we used `&` over Ruby's `&&` keyword.**
-That's because the context of execution of these validations isn't a plain lambda, but something richer.
-
-For real world projects, we want to support common scenarios without the need of reinventing the wheel ourselves. Scenarios like _password confirmation_, _size check_ are already prepackaged with `Hanami::Validations`.
-
-
-β **For this reason, we don't allow any arbitrary Ruby code to be executed, but only well defined predicates.** β
-
-### Predicates
-
-To meet our needs, `Hanami::Validations` has an extensive collection of **built-in** predicates. **A predicate is the expression of a business requirement** (e.g. _size greater than_). The chain of several predicates determines if input data is valid or not.
-
-We already met `filled?` and `size?`, now letβs introduce the rest of them. They capture **common use cases with web forms**.
-
-### Array
-
-It checks if the the given value is an array, and iterates through its elements to perform checks on each of them.
-
-```ruby
-required(:codes) { array? { each { int? } } }
-```
-
-This example checks if `codes` is an array and if all the elements are integers, whereas the following example checks there are a minimum of 2 elements and all elements are strings.
-
-```ruby
-required(:codes) { array? { min_size?(2) & each { str? } } }
-```
-
-#### Emptiness
-
-It checks if the given value is empty or not. It is designed to works with strings and collections (array and hash).
-
-```ruby
-required(:tags) { empty? }
-```
-
-#### Equality
-
-This predicate tests if the input is equal to a given value.
-
-```ruby
-required(:magic_number) { eql?(23) }
-```
-
-Ruby types are respected: `23` (an integer) is only equal to `23`, and not to `"23"` (a string). See _Type Safety_ section.
-
-#### Exclusion
-
-It checks if the input is **not** included by a given collection. This collection can be an array, a set, a range or any object that responds to `#include?`.
-
-```ruby
-required(:genre) { excluded_from?(%w(pop dance)) }
-```
-
-#### Format
-
-This is a predicate that works with a regular expression to match it against data input.
-
-```ruby
-require 'uri'
-HTTP_FORMAT = URI.regexp(%w(http https))
-
-required(:url) { format?(HTTP_FORMAT) }
-```
-
-#### Greater Than
-
-This predicate works with numbers to check if input is **greater than** a given threshold.
-
-```ruby
-required(:age) { gt?(18) }
-```
-
-#### Greater Than Equal
-
-This is an _open boundary_ variation of `gt?`. It checks if an input is **greater than or equal** of a given number.
-
-```ruby
-required(:age) { gteq?(19) }
-```
-
-#### Inclusion
-
-This predicate is the opposite of `#exclude?`: it verifies if the input is **included** in the given collection.
-
-```ruby
-required(:genre) { included_in?(%w(rock folk)) }
-```
-
-#### Less Than
-
-This is the complement of `#gt?`: it checks for **less than** numbers.
-
-```ruby
-required(:age) { lt?(7) }
-```
-
-#### Less Than Equal
-
-Similarly to `#gteq?`, this is the _open bounded_ version of `#lt?`: an input is valid if itβs **less than or equal** to a number.
-
-```ruby
-required(:age) { lteq?(6) }
-```
-
-#### Filled
-
-Itβs a predicate that ensures data input is filled, that means **not** `nil` or blank (`""`) or empty (in case we expect a collection).
-
-```ruby
-required(:name) { filled? } # string
-required(:languages) { filled? } # collection
-```
-
-#### Minimum Size
-
-This verifies that the size of the given input is at least of the specified value.
-
-```ruby
-required(:password) { min_size?(12) }
-```
-
-#### Maximum Size
-
-This verifies that the size of the given input is at max of the specified value.
-
-```ruby
-required(:name) { max_size?(128) }
-```
-
-#### None
-
-This verifies if the given input is `nil`. Blank strings (`""`) wonβt pass this test and return `false`.
-
-```ruby
-required(:location) { none? }
-```
-
-#### Size
-
-It checks if the size of input data is: a) exactly the same of a given quantity or b) it falls into a range.
-
-```ruby
-required(:two_factor_auth_code) { size?(6) } # exact
-required(:password) { size?(8..32) } # range
-```
-
-The check works with strings and collections.
-
-```ruby
-required(:answers) { size?(2) } # only 2 answers are allowed
-```
-
-This predicate works with objects that respond to `#size`. Until now we have seen strings and arrays being analysed by this validation, but there is another interesting usage: files.
-
-When a user uploads a file, the web server sets an instance of `Tempfile`, which responds to `#size`. That means we can validate the weight in bytes of file uploads.
-
-```ruby
-MEGABYTE = 1024 ** 2
-
-required(:avatar) { size?(1..(5 * MEGABYTE)) }
-```
diff --git a/source/guides/1.1/validations/custom-predicates.md b/source/guides/1.1/validations/custom-predicates.md
deleted file mode 100644
index a719d9172..000000000
--- a/source/guides/1.1/validations/custom-predicates.md
+++ /dev/null
@@ -1,112 +0,0 @@
----
-title: Guides - Custom Predicates
-version: 1.1
----
-
-# Custom Predicates
-
-We have seen that built-in predicates as an expressive tool to get our job done with common use cases.
-
-But what if our case is not common? We can define our own custom predicates.
-
-### Inline Custom Predicates
-
-If we are facing a really unique validation that don't need to be reused across our code, we can opt for an inline custom predicate:
-
-```ruby
-require 'hanami/validations'
-
-class Signup
- include Hanami::Validations
-
- predicate :url?, message: 'must be an URL' do |current|
- # ...
- end
-
- validations do
- required(:website) { url? }
- end
-end
-```
-
-### Global Custom Predicates
-
-If our goal is to share common used custom predicates, we can include them in a module to use in all our validators:
-
-```ruby
-require 'hanami/validations'
-
-module MyPredicates
- include Hanami::Validations::Predicates
-
- self.messages_path = 'config/errors.yml'
-
- predicate(:email?) do |current|
- current.match(/.../)
- end
-end
-```
-
-We have defined a module `MyPredicates` with the purpose to share its custom predicates with all the validators that need them.
-
-```ruby
-require 'hanami/validations'
-require_relative 'my_predicates'
-
-class Signup
- include Hanami::Validations
- predicates MyPredicates
-
- validations do
- required(:email) { email? }
- end
-end
-```
-
-### Internationalization (I18n)
-
-```ruby
-require 'hanami/validations'
-
-module MyPredicates
- include Hanami::Validations::Predicates
-
- self.messages_path = 'config/errors.yml'
-
- predicate(:uuid?) do |input|
- !/[0-9a-f]{8}-
- [0-9a-f]{4}-
- [0-9a-f]{4}-
- [0-9a-f]{4}-
- [0-9a-f]{12}/x.match(input).nil?
- end
-end
-```
-
-```ruby
-require 'hanami/validations'
-require_relative 'my_predicates'
-
-module Web::Controllers::Signup
- class Params < Hanami::Action::Params
- predicates MyPredicates
-
- validations do
- required(:id).filled(:uuid?)
- end
- end
-end
-```
-
-```ruby
-module Web::Controllers::Signup
- class Create
- include Web::Action
- params Params
-
- def call(params)
- # ...
- end
- end
-end
-```
diff --git a/source/guides/1.1/validations/overview.md b/source/guides/1.1/validations/overview.md
deleted file mode 100644
index f66ae6e61..000000000
--- a/source/guides/1.1/validations/overview.md
+++ /dev/null
@@ -1,27 +0,0 @@
----
-title: Guides - Validations Overview
-version: 1.1
----
-
-# Overview
-
-`Hanami::Validations` is a mixin that, once included by an object, adds lightweight set of validations to it.
-
-It works with input hashes and lets us to define a set of validation rules **for each** key/value pair. These rules are wrapped by lambdas (or special DSL) that check the input for a specific key to determine if it's valid or not. To do that, we translate business requirements into predicates that are chained together with Ruby _faux boolean logic_ operators (eg. `&` or `|`).
-
-Think of a signup form. We need to ensure data integrity for the `name` field with the following rules. It is required, it has to be: filled **and** a string **and** its size must be greater than 3 chars, but lesser than 64. Hereβs the code, **read it aloud** and notice how it perfectly expresses our needs for `name`.
-
-```ruby
-class Signup
- include Hanami::Validations
-
- validations do
- required(:name) { filled? & str? & size?(3..64) }
- end
-end
-
-result = Signup.new(name: "Luca").validate
-result.success? # => true
-```
-
-There is more that `Hanami::Validations` can do: **type safety**, **composition**, **complex data structures**, **built-in and custom predicates**.
diff --git a/source/guides/1.1/views/basic-usage.md b/source/guides/1.1/views/basic-usage.md
deleted file mode 100644
index 433d3db3d..000000000
--- a/source/guides/1.1/views/basic-usage.md
+++ /dev/null
@@ -1,118 +0,0 @@
----
-title: Guides - Views Basic Usage
-version: 1.1
----
-
-# Basic Usage
-
-In the [previous section](/guides/1.1/views/overview) we generated a view. Let's use it.
-
-## Default Rendering
-
-First, we edit the corresponding template:
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-Dashboard
-```
-
-By visiting `/dashboard`, we should see `Dashboard ` in our browser.
-
-Again we should look at the naming convention.
-Our view is `Web::Views::Dashboard::Index`, while the file name of the template is `web/templates/dashboard/index`.
-
-
- For a given view Web::Views::Dashboard::Index
, the corresponding template MUST be available at apps/web/templates/dashboard/index.html.erb
.
-
-
-### Context
-
-While rendering a template, variable lookups requested by the template go to a view _context_.
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-<%= title %>
-```
-
-If we amend our template by adding an interpolated variable, the view is responsible for providing it.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
-
- def title
- 'Dashboard'
- end
- end
-end
-```
-
-The view now responds to `#title` by implementing it as a concrete method.
-We still see `Dashboard ` when we visit `/dashboard`.
-
-### Exposures
-
-There is another source for our context: [_exposures_](/guides/1.1/actions/exposures).
-They are a payload that comes from the action.
-
-```ruby
-# apps/web/controllers/dashboard/index.rb
-module Web::Controllers::Dashboard
- class Index
- include Web::Action
- expose :title
-
- def call(params)
- @title = 'Dashboard'
- end
- end
-end
-```
-
-We can remove `#title` from our view, to get the same output when accessing `/dashboard`.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- end
-end
-```
-
-
-Rendering context for a template is made of view methods and exposures.
-
-
-## Custom Rendering
-
-Hanami performs rendering by calling `#render` on a view and it expects a string in return.
-The benefit of an object-oriented approach is the ability to easily diverge from default behavior.
-
-We can override that method to define a custom rendering policy.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
-
- def render
- raw %(Dashboard )
- end
- end
-end
-```
-
-Once again our output is still the same, but the template isn't used at all.
-
-
-If a view overrides #render
the output MUST be a string that will be the body of the response.
-The template isn't used and it can be deleted.
-
-
-## Bypass Rendering
-
-If an action assigns the body of the response with `#body=`, the rendering of the view is [bypassed](/guides/1.1/actions/basic-usage).
diff --git a/source/guides/1.1/views/custom-error-pages.md b/source/guides/1.1/views/custom-error-pages.md
deleted file mode 100644
index 11258d828..000000000
--- a/source/guides/1.1/views/custom-error-pages.md
+++ /dev/null
@@ -1,22 +0,0 @@
----
-title: Guides - Custom Error Pages
-version: 1.1
----
-
-# Custom Error Pages
-
-When an unsuccessful request is returned, there are some special pages that a Hanami application presents to users.
-These pages have a generic graphic and some basic information like the [HTTP status code](https://en.wikipedia.org/wiki/List_of_HTTP_status_codes) and the message.
-
-Hanami allows us to customize them on a per-application basis.
-We just need to create a template with the corresponding HTTP code as the filename (e.g. `apps/web/templates/500.html.erb`).
-From then on, all 500 errors (Internal Server Error) will be presented using that template (like for an exception that is not rescued).
-
-
- A template for a custom error page MUST be named after the HTTP code that it targets.
- Example: 500.html.erb
for Internal Server Error (500).
-
-
-
- A template for a custom error page MUST be placed under the templates
directory of the application.
-
diff --git a/source/guides/1.1/views/layouts.md b/source/guides/1.1/views/layouts.md
deleted file mode 100644
index 85c88c8b4..000000000
--- a/source/guides/1.1/views/layouts.md
+++ /dev/null
@@ -1,146 +0,0 @@
----
-title: Guides - View Layouts
-version: 1.1
----
-
-# Layouts
-
-Layouts are special views, that render the _"fixed"_ part of the HTML markup.
-This is the part that doesn't change from page to page (perhaps navigation, sidebar, header, footer, etc.)
-
-When we generate a new application, there is a default layout called `Web::Views::ApplicationLayout` with a `apps/web/templates/application.html.erb` template.
-It comes with a very basic HTML5 wireframe.
-
-```erb
-
-
-
- Web
-
-
- <%= yield %>
-
-
-```
-
-The most interesting part is `<%= yield %>`.
-It's replaced at the runtime with the output of a view.
-**The order for rendering is first the view, and then the layout.**
-
-The context for a layout template is made of the layout and the current view.
-The latter has higher priority.
-
-Imagine having the following line `<%= page_title %> `.
-If both the layout and the view implement `page_title`, Hanami will use the one from the view.
-
-## Configure Layout
-
-The default layout is defined in an application's configuration.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- layout :application
- end
- end
-end
-```
-
-
-Hanami transforms the layout name in the application's configuration, by appending the Layout
suffix. For example, layout :application
corresponds to Web::Views::ApplicationLayout
.
-
-
-If we want to disable a layout for a view, we can use a DSL for that:
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- layout false
- end
-end
-```
-
-If we want to turn off this feature entirely, we can set `layout nil` into the application's configuration.
-
-## Using Multiple Template Layouts
-
-Sometimes it's useful to have more than one layout.
-For example, if the `application.html.erb` template contains navigation elements, and we want an entirely different layout, without navigation elements, for a login page, we can create a `login.html.erb` layout template.
-
-Assuming we have a `Web::Actions::UserSessions::New` action to log a user in, we can create a `login.html.erb` template right next to the default `application.html.erb` in `apps/web/templates/`.
-
-Then we need to create a new `Web::Views::LoginLayout` class, which will use the new layout template. This file can be named `app/web/views/login_layout.rb`(right next to the default `application_layout.rb`):
-
-```ruby
-module Web
- module Views
- class LoginLayout
- include Web::Layout
- end
- end
-end
-```
-
-Now, in our `app/web/views/user_sessions/new.rb` we can specify you'd like to use the login layout for this View:
-
-```ruby
-module Web::Views::UserSessions
- class New
- include Web::View
- layout :login
- end
-end
-```
-
-And we can add `layout :login` to any other View in this app that should use this same layout.
-
-## Optional Content
-
-Sometimes it's useful to render content only on certain pages.
-For example, this could be used to have page-specific javascript.
-
-Given the following template for a layout:
-
-```erb
-
-
-
-
-
-
- <%= local :javascript %>
-
-
-
-```
-
-With following views:
-
-```ruby
-module Web::Views::Books
- class Index
- include Web::View
- end
-end
-```
-
-and
-
-```ruby
-module Web::Views::Books
- class Show
- include Web::View
-
- def javascript
- raw %()
- end
- end
-end
-```
-
-The first view doesn't respond to `#javascript`, so it safely ignores it.
-Our second object (`Web::Views::Books::Show`) responds to that method, so the result will be included in the final markup.
diff --git a/source/guides/1.1/views/mime-types.md b/source/guides/1.1/views/mime-types.md
deleted file mode 100644
index 6fd9c1690..000000000
--- a/source/guides/1.1/views/mime-types.md
+++ /dev/null
@@ -1,79 +0,0 @@
----
-title: Guides - MIME Types
-version: 1.1
----
-
-# MIME Types
-
-A view can handle several MIME Types. Before diving into this subject, please consider to read how actions handle [MIME Types](/guides/1.1/actions/mime-types).
-
-It's important to highlight the correlation between the _format_ and template name.
-For a given MIME Type, Rack (and then Hanami) associate a _format_ for it.
-XML is mapped from `application/xml` to `:xml`, HTML is `text/html` and becomes `:html` for us.
-
-
-Format MUST be the first extension of the template file name. Eg dashboard/index.html.*
.
-
-
-## Default Rendering
-
-If our action (`Web::Controllers::Dashboard::Index`) is handling a JSON request, and we have defined a template for it (`apps/web/templates/dashboard/index.json.erb`), our view will use it for rendering.
-
-```erb
-# apps/web/templates/dashboard/index.json.erb
-{"foo":"bar"}
-```
-
-```shell
-% curl -H "Accept: application/json" http://localhost:2300/dashboard
-{"foo":"bar"}
-```
-
-We're still able to request HTML format.
-
-```erb
-# apps/web/templates/dashboard/index.html.erb
-Dashboard
-```
-
-```shell
-% curl -H "Accept: text/html" http://localhost:2300/dashboard
-Dashboard
-```
-
-In case we request an unsupported MIME Type, our application will raise an error.
-
-```shell
-% curl -H "Accept: application/xml" http://localhost:2300/dashboard
-Hanami::View::MissingTemplateError: Can't find template "dashboard/index" for "xml" format.
-```
-
-## View For Specific Format
-
-This scenario works well if the presentational logic of a view can be applied for all the format templates that it handles.
-What if we want to have a [custom rendering](/guides/1.1/views/basic-usage) or different presentational logic?
-
-We can inherit from our view and declare that our subclass only handles a specific format.
-
-```ruby
-# apps/web/views/dashboard/json_index.rb
-require_relative './index'
-
-module Web::Views::Dashboard
- class JsonIndex < Index
- format :json
-
- def render
- raw JSON.generate({foo: 'bar'})
- end
- end
-end
-```
-
-JSON requests for `/dashboard`, will be handled by our `JsonIndex`.
-
-
-There is NO convention between the handled format and the class name. The important part is format :json
.
-
-
-With the example above we took advantage of custom rendering to not use the template and let our serializer to return JSON for us.
diff --git a/source/guides/1.1/views/overview.md b/source/guides/1.1/views/overview.md
deleted file mode 100644
index 44368554e..000000000
--- a/source/guides/1.1/views/overview.md
+++ /dev/null
@@ -1,69 +0,0 @@
----
-title: Guides - Views Overview
-version: 1.1
----
-
-# Overview
-
-A view is an object that's responsible for rendering a template.
-
-In a full stack Hanami application, an incoming HTTP request goes through the [router](/guides/1.1/routing/overview), it instantiates and calls an [action](/guides/1.1/actions/overview), which sets the status code and the headers for the response.
-The last bit is the body, which is set by the corresponding view's output.
-
-## A Simple View
-
-Hanami ships a generator for actions that creates a view and a template.
-
-```shell
-% hanami generate action web dashboard#index
- insert apps/web/config/routes.rb
- create spec/web/controllers/dashboard/index_spec.rb
- create apps/web/controllers/dashboard/index.rb
- create apps/web/views/dashboard/index.rb
- create apps/web/templates/dashboard/index.html.erb
- create spec/web/views/dashboard/index_spec.rb
-```
-
-Looking at those file names, we have an action called `Web::Controllers::Dashboard::Index` (read about [actions naming](/guides/1.1/actions/overview)).
-Our view has a similar name: `Web::Views::Dashboard::Index`.
-
-Let's examine the view:
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- end
-end
-```
-
-### Naming
-
-That file begins with a module declaration which is similar to the [action naming structure](/guides/1.1/actions/overview).
-The only difference is that we use `Views` module instead of `Controllers`.
-**All the views are nested under it.**
-This module is generated at the runtime for us, when the application starts.
-
-
- For a given application named Web
, views are available under Web::Views
.
-
-
-**This symmetry is really important at run time.**
-After the action has finished its job, control passes to the framework which looks for the matching view.
-
-
- For a given action named Web::Controllers::Home::Index
which is handling a request, Hanami will look for a corresponding Web::Views::Home::Index
view.
-
-
-### View Module
-
-All the main Hanami components are mixins meant to be included.
-Because a Hanami Container can run multiple applications within the same Ruby process, the configurations of these different components should be kept separated.
-
-In our example, we have a directive `include Web::View`.
-That means our view will behave according to the configuration of the `Web` application.
-
-
- For a given application named Web
, the view mixin to include is Web::View
.
-
diff --git a/source/guides/1.1/views/share-code.md b/source/guides/1.1/views/share-code.md
deleted file mode 100644
index d61a565ec..000000000
--- a/source/guides/1.1/views/share-code.md
+++ /dev/null
@@ -1,52 +0,0 @@
----
-title: Guides - View Share Code
-version: 1.1
----
-
-# Share Code
-
-## Prepare
-
-In our settings (`apps/web/application.rb`), there is a code block that allows to share the code for **all the views** of our application.
-When a view includes the `Web::View` module, that block code is yielded within the context of that class.
-This is heavily inspired by Ruby Module and its `included` hook.
-
-Imagine we have an application that only renders JSON.
-For each view we should specify the handled format. This can be tedious to do by hand, but we can easily DRY our code.
-
-We craft a module in `apps/web/views/accept_json.rb`.
-
-```ruby
-# apps/web/views/accept_json.rb
-module Web::Views
- module AcceptJson
- def self.included(view)
- view.class_eval do
- format :json
- end
- end
- end
-end
-```
-
-Then we can load the file and include the module in **all** the views of our application, using view.prepare.
-
-```ruby
-# apps/web/application.rb
-require_relative './views/accept_json'
-
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- view.prepare do
- include Web::Views::AcceptJson
- end
- end
- end
-end
-```
-
-
-Code included via prepare
is available for ALL the views of an application.
-
diff --git a/source/guides/1.1/views/templates.md b/source/guides/1.1/views/templates.md
deleted file mode 100644
index 98ffbb780..000000000
--- a/source/guides/1.1/views/templates.md
+++ /dev/null
@@ -1,216 +0,0 @@
----
-title: Guides - View Templates
-version: 1.1
----
-
-# Templates
-
-A template is a file that describes the body of a response.
-It is rendered by bounding the context of a view and using a _template engine_.
-
-## Naming
-
-For simplicity sake, there is a correlation between the view class name and the template file name.
-It's the translation of the name into a path: from `Dashboard::Index` to `dashboard/index`.
-
-The remaining part is made of multiple file extensions.
-The first is relative to the **_format_** and the latter is for the **_template engine_**.
-
-
-For a given view named Web::Views::Dashboard::Index
, there must be at least one template dashboard/index.[format].[engine]
under the templates directory.
-
-
-## Nested Templates
-To render a partial in other template call `render` method with `partial` option:
-
-```
-# Given a partial under:
-# templates/shared/_sidebar.html.erb
-#
-# In the layout template:
-# templates/application.html.erb
-#
-<%= render partial: 'shared/sidebar' %>
-```
-
-To render a template in other template call `render` method with `template` option:
-
-```
-# Given a template under:
-# templates/articles/index.html.erb
-#
-# In the layout template:
-# templates/application.html.erb
-#
-<%= render template: 'articles/index' %>
-```
-
-### Custom Template
-
-If we want to associate a different template to a view, we can use `template`.
-
-```ruby
-# apps/web/views/dashboard/index.rb
-module Web::Views::Dashboard
- class Index
- include Web::View
- template 'home/index'
- end
-end
-```
-
-Our view will look for `apps/web/templates/home/index.*` template.
-
-## Engines
-
-Hanami looks at the last extension of a template file name to decide which engine to use (eg `index.html.erb` will use ERb).
-The builtin rendering engine is [ERb](http://en.wikipedia.org/wiki/ERuby), but Hanami supports countless rendering engines out of the box.
-
-This is a list of the supported engines.
-They are listed in order of **higher precedence**, for a given extension.
-For instance, if [ERubis](http://www.kuwata-lab.com/erubis/) is loaded, it will be preferred over ERb to render `.erb` templates.
-
-
-
- Engine
- Extensions
-
-
- Erubis
- erb, rhtml, erubis
-
-
- ERb
- erb, rhtml
-
-
- Redcarpet
- markdown, mkd, md
-
-
- RDiscount
- markdown, mkd, md
-
-
- Kramdown
- markdown, mkd, md
-
-
- Maruku
- markdown, mkd, md
-
-
- BlueCloth
- markdown, mkd, md
-
-
- Asciidoctor
- ad, adoc, asciidoc
-
-
- Builder
- builder
-
-
- CSV
- rcsv
-
-
- CoffeeScript
- coffee
-
-
- WikiCloth
- wiki, mediawiki, mw
-
-
- Creole
- wiki, creole
-
-
- Etanni
- etn, etanni
-
-
- Haml
- haml
-
-
- Less
- less
-
-
- Liquid
- liquid
-
-
- Markaby
- mab
-
-
- Nokogiri
- nokogiri
-
-
- Plain
- html
-
-
- RDoc
- rdoc
-
-
- Radius
- radius
-
-
- RedCloth
- textile
-
-
- Sass
- sass
-
-
- Scss
- scss
-
-
- Slim
- slim
-
-
- String
- str
-
-
- Yajl
- yajl
-
-
-
-In order to use a different template engine we need to bundle the gem and to use the right file extension.
-
-```haml
-# app/web/templates/dashboard/index.html.haml
-%h1 Dashboard
-```
-
-## Directory
-
-Templates are located in the default directory `templates`, located under an application's directory `apps/web`.
-If we want to customize this location, we can amend our application's configuration.
-
-```ruby
-# apps/web/application.rb
-module Web
- class Application < Hanami::Application
- configure do
- # ...
- templates 'path/to/templates'
- end
- end
-end
-```
-
-The application will now look for templates under `apps/web/path/to/templates`.
diff --git a/source/guides/1.1/views/testing.md b/source/guides/1.1/views/testing.md
deleted file mode 100644
index fe9c612e0..000000000
--- a/source/guides/1.1/views/testing.md
+++ /dev/null
@@ -1,86 +0,0 @@
----
-title: Guides - View Testing
-version: 1.1
----
-
-# View Testing
-
-One of the advantages of views as objects is that we can unit test them.
-We can both understand if a specific presentational logic behaves correctly and/or assert the contents of the rendered markup.
-
-For the following example we're gonna use RSpec for the concise syntax for test doubles.
-
-```ruby
-# spec/web/views/books/show_spec.rb
-require 'spec_helper'
-require_relative '../../../../apps/web/views/books/show'
-
-RSpec.describe Web::Views::Books::Show do
- let(:exposures) { Hash[book: double('book', price: 1.00), current_user: user, params: {}] }
- let(:template) { Hanami::View::Template.new('apps/web/templates/books/show.html.erb') }
- let(:view) { Web::Views::Home::Another.new(template, exposures) }
- let(:rendered) { view.render }
- let(:user) { double('user', admin?: false) }
-
- describe "price" do
- it "returns formatted price" do
- expect(view.formatted_price).to eq "$1.00"
- end
- end
-
- describe "edit link" do
- it "doesn't show it by default" do
- expect(rendered).to_not match %(edit )
- end
-
- context "when admin" do
- let(:user) { double('user', admin?: true) }
-
- it "shows it" do
- expect(rendered).to match %(edit )
- end
- end
- end
-end
-```
-
-The first part of the test code above is about book's formatting price.
-This presentational logic is verified by asserting the returning value of `view.formatted_price`.
-
-The remaining code is about permissions related logic: the edit link must be rendered only if the current user is an admin.
-This is tested by looking at the output of the template.
-
-
- Asserting presentational logic directly via view's methods, or indirectly via rendered markup are two EQUIVALENT ways.
-
-
-Notice that `exposures` includes an unused `params` key.
-While this is not strictly required,
-we recommend providing it since it's expected by some standard view helpers (e.g. form helpers).
-
-Let's have a look at the corresponding production code.
-
-```ruby
-# apps/web/views/books/show.rb
-module Web::Views::Books
- class Show
- include Web::View
-
- def formatted_price
- "$#{ format_number book.price }"
- end
-
- def edit_link
- if can_edit_book?
- link_to "Edit", routes.edit_book_path(id: book.id)
- end
- end
-
- private
-
- def can_edit_book?
- current_user.admin?
- end
- end
-end
-```
diff --git a/source/guides/index.erb b/source/guides/index.erb
deleted file mode 100644
index 1aa2052e0..000000000
--- a/source/guides/index.erb
+++ /dev/null
@@ -1,13 +0,0 @@
----
-layout: false
----
-
-
-
- Hanami | Guides
-
-
-
- Please visit API docs for our latest stable version .
-
-
diff --git a/source/images/companies/ascenda-loyalty.png b/source/images/companies/ascenda-loyalty.png
new file mode 100644
index 000000000..e89f0dd6f
Binary files /dev/null and b/source/images/companies/ascenda-loyalty.png differ
diff --git a/source/images/companies/flooring-stores.png b/source/images/companies/flooring-stores.png
new file mode 100644
index 000000000..e3569f895
Binary files /dev/null and b/source/images/companies/flooring-stores.png differ
diff --git a/source/images/companies/hippo.png b/source/images/companies/hippo.png
new file mode 100644
index 000000000..4fcdefc65
Binary files /dev/null and b/source/images/companies/hippo.png differ
diff --git a/source/images/companies/marozed.png b/source/images/companies/marozed.png
new file mode 100644
index 000000000..430de6643
Binary files /dev/null and b/source/images/companies/marozed.png differ
diff --git a/source/images/companies/playguide.png b/source/images/companies/playguide.png
new file mode 100644
index 000000000..eada385c9
Binary files /dev/null and b/source/images/companies/playguide.png differ
diff --git a/source/images/companies/ppe-analytics.png b/source/images/companies/ppe-analytics.png
new file mode 100644
index 000000000..de2ec2a58
Binary files /dev/null and b/source/images/companies/ppe-analytics.png differ
diff --git a/source/javascripts/application.js b/source/javascripts/application.js
index d2b1fd49c..56d864838 100644
--- a/source/javascripts/application.js
+++ b/source/javascripts/application.js
@@ -11,4 +11,8 @@ $(function () {
$("select.mobile-guides").change(function() {
window.location = $(this).find(":selected").val();
});
+
+ $toc.find('span').click(function() {
+ $(this).parent().toggleClass('opened')
+ })
})
diff --git a/source/javascripts/excerpt-search.js b/source/javascripts/excerpt-search.js
deleted file mode 100644
index 639a14351..000000000
--- a/source/javascripts/excerpt-search.js
+++ /dev/null
@@ -1,47 +0,0 @@
-function excerptSearch(terms, text, options) {
- var terms = terms || "",
- text = text || "",
- options = options || {};
-
- options.padding = options.padding || 100;
- options.highlightClass = options.highlightClass || "highlight";
-
- //join arrays into a string to sanitize the regex
- if (terms instanceof Array) {
- terms = terms.join(" ");
- }
- //sanitize the regex
- terms = terms.replace(/[\-\[\]\/\{\}\(\)\*\+\?\.\\\^\$\|]/g, "\\$&");
-
- //now split back into array
- terms = terms.split(" ");
-
- var termRegex = new RegExp("(" + terms.join("|") + ")", "gi"),
- location = text.search(termRegex);
- if (location !== -1) {
- //calculate the from - to positions
- //add +1 so that we can go back and make sure we ended on a solid word boundary.
- //this prevents us from chopping off a full word unecessarily if the padding
- //happens to fall directly on a word boundary
- var f = Math.max(0, location - (options.padding + 1)),
- t = Math.min(text.length, location + (options.padding + 1)),
- excerpt = text.substring(f,t);
-
- //ensure we start and end on a word boundary
- if (f !== 0) {
- excerpt = excerpt.replace(/^\S*\s/, "");
- }
- if (t !== text.length) {
- excerpt = excerpt.replace(/\s\S*$/, "");
- }
-
- //now we highlight the search term
- excerpt = excerpt.replace(termRegex, function(s) {
- return "" + s + " "
- });
- return excerpt;
- } else {
- return false;
- }
-
-}
diff --git a/source/javascripts/jquery.autocomplete.min.js b/source/javascripts/jquery.autocomplete.min.js
deleted file mode 100644
index 3d00147ea..000000000
--- a/source/javascripts/jquery.autocomplete.min.js
+++ /dev/null
@@ -1,8 +0,0 @@
-/**
-* Ajax Autocomplete for jQuery, version 1.4.1
-* (c) 2017 Tomas Kirda
-*
-* Ajax Autocomplete for jQuery is freely distributable under the terms of an MIT-style license.
-* For details, see the web site: https://github.com/devbridge/jQuery-Autocomplete
-*/
-!function(a){"use strict";"function"==typeof define&&define.amd?define(["jquery"],a):a("object"==typeof exports&&"function"==typeof require?require("jquery"):jQuery)}(function(a){"use strict";function b(c,d){var e=this;e.element=c,e.el=a(c),e.suggestions=[],e.badQueries=[],e.selectedIndex=-1,e.currentValue=e.element.value,e.timeoutId=null,e.cachedResponse={},e.onChangeTimeout=null,e.onChange=null,e.isLocal=!1,e.suggestionsContainer=null,e.noSuggestionsContainer=null,e.options=a.extend({},b.defaults,d),e.classes={selected:"autocomplete-selected",suggestion:"autocomplete-suggestion"},e.hint=null,e.hintValue="",e.selection=null,e.initialize(),e.setOptions(d)}function c(a,b,c){return-1!==a.value.toLowerCase().indexOf(c)}function d(b){return"string"==typeof b?a.parseJSON(b):b}function e(a,b){if(!b)return a.value;var c="("+g.escapeRegExChars(b)+")";return a.value.replace(new RegExp(c,"gi"),"$1 ").replace(/&/g,"&").replace(//g,">").replace(/"/g,""").replace(/<(\/?strong)>/g,"<$1>")}function f(a,b){return''+b+"
"}var g=function(){return{escapeRegExChars:function(a){return a.replace(/[|\\{}()[\]^$+*?.]/g,"\\$&")},createNode:function(a){var b=document.createElement("div");return b.className=a,b.style.position="absolute",b.style.display="none",b}}}(),h={ESC:27,TAB:9,RETURN:13,LEFT:37,UP:38,RIGHT:39,DOWN:40},i=a.noop;b.utils=g,a.Autocomplete=b,b.defaults={ajaxSettings:{},autoSelectFirst:!1,appendTo:"body",serviceUrl:null,lookup:null,onSelect:null,width:"auto",minChars:1,maxHeight:300,deferRequestBy:0,params:{},formatResult:e,formatGroup:f,delimiter:null,zIndex:9999,type:"GET",noCache:!1,onSearchStart:i,onSearchComplete:i,onSearchError:i,preserveInput:!1,containerClass:"autocomplete-suggestions",tabDisabled:!1,dataType:"text",currentRequest:null,triggerSelectOnValidInput:!0,preventBadQueries:!0,lookupFilter:c,paramName:"query",transformResult:d,showNoSuggestionNotice:!1,noSuggestionNotice:"No results",orientation:"bottom",forceFixPosition:!1},b.prototype={initialize:function(){var c,d=this,e="."+d.classes.suggestion,f=d.classes.selected,g=d.options;d.element.setAttribute("autocomplete","off"),d.noSuggestionsContainer=a('
').html(this.options.noSuggestionNotice).get(0),d.suggestionsContainer=b.utils.createNode(g.containerClass),c=a(d.suggestionsContainer),c.appendTo(g.appendTo||"body"),"auto"!==g.width&&c.css("width",g.width),c.on("mouseover.autocomplete",e,function(){d.activate(a(this).data("index"))}),c.on("mouseout.autocomplete",function(){d.selectedIndex=-1,c.children("."+f).removeClass(f)}),c.on("click.autocomplete",e,function(){d.select(a(this).data("index"))}),c.on("click.autocomplete",function(){clearTimeout(d.blurTimeoutId)}),d.fixPositionCapture=function(){d.visible&&d.fixPosition()},a(window).on("resize.autocomplete",d.fixPositionCapture),d.el.on("keydown.autocomplete",function(a){d.onKeyPress(a)}),d.el.on("keyup.autocomplete",function(a){d.onKeyUp(a)}),d.el.on("blur.autocomplete",function(){d.onBlur()}),d.el.on("focus.autocomplete",function(){d.onFocus()}),d.el.on("change.autocomplete",function(a){d.onKeyUp(a)}),d.el.on("input.autocomplete",function(a){d.onKeyUp(a)})},onFocus:function(){var a=this;a.fixPosition(),a.el.val().length>=a.options.minChars&&a.onValueChange()},onBlur:function(){var a=this;a.blurTimeoutId=setTimeout(function(){a.hide()},200)},abortAjax:function(){var a=this;a.currentRequest&&(a.currentRequest.abort(),a.currentRequest=null)},setOptions:function(b){var c=this,d=c.options;this.options=a.extend({},d,b),c.isLocal=a.isArray(d.lookup),c.isLocal&&(d.lookup=c.verifySuggestionsFormat(d.lookup)),d.orientation=c.validateOrientation(d.orientation,"bottom"),a(c.suggestionsContainer).css({"max-height":d.maxHeight+"px",width:d.width+"px","z-index":d.zIndex})},clearCache:function(){this.cachedResponse={},this.badQueries=[]},clear:function(){this.clearCache(),this.currentValue="",this.suggestions=[]},disable:function(){var a=this;a.disabled=!0,clearTimeout(a.onChangeTimeout),a.abortAjax()},enable:function(){this.disabled=!1},fixPosition:function(){var b=this,c=a(b.suggestionsContainer),d=c.parent().get(0);if(d===document.body||b.options.forceFixPosition){var e=b.options.orientation,f=c.outerHeight(),g=b.el.outerHeight(),h=b.el.offset(),i={top:h.top,left:h.left};if("auto"===e){var j=a(window).height(),k=a(window).scrollTop(),l=-k+h.top-f,m=k+j-(h.top+g+f);e=Math.max(l,m)===l?"top":"bottom"}if("top"===e?i.top+=-f:i.top+=g,d!==document.body){var n,o=c.css("opacity");b.visible||c.css("opacity",0).show(),n=c.offsetParent().offset(),i.top-=n.top,i.left-=n.left,b.visible||c.css("opacity",o).hide()}"auto"===b.options.width&&(i.width=b.el.outerWidth()+"px"),c.css(i)}},isCursorAtEnd:function(){var a,b=this,c=b.el.val().length,d=b.element.selectionStart;return"number"==typeof d?d===c:document.selection?(a=document.selection.createRange(),a.moveStart("character",-c),c===a.text.length):!0},onKeyPress:function(a){var b=this;if(!b.disabled&&!b.visible&&a.which===h.DOWN&&b.currentValue)return void b.suggest();if(!b.disabled&&b.visible){switch(a.which){case h.ESC:b.el.val(b.currentValue),b.hide();break;case h.RIGHT:if(b.hint&&b.options.onHint&&b.isCursorAtEnd()){b.selectHint();break}return;case h.TAB:if(b.hint&&b.options.onHint)return void b.selectHint();if(-1===b.selectedIndex)return void b.hide();if(b.select(b.selectedIndex),b.options.tabDisabled===!1)return;break;case h.RETURN:if(-1===b.selectedIndex)return void b.hide();b.select(b.selectedIndex);break;case h.UP:b.moveUp();break;case h.DOWN:b.moveDown();break;default:return}a.stopImmediatePropagation(),a.preventDefault()}},onKeyUp:function(a){var b=this;if(!b.disabled){switch(a.which){case h.UP:case h.DOWN:return}clearTimeout(b.onChangeTimeout),b.currentValue!==b.el.val()&&(b.findBestHint(),b.options.deferRequestBy>0?b.onChangeTimeout=setTimeout(function(){b.onValueChange()},b.options.deferRequestBy):b.onValueChange())}},onValueChange:function(){var b=this,c=b.options,d=b.el.val(),e=b.getQuery(d);return b.selection&&b.currentValue!==e&&(b.selection=null,(c.onInvalidateSelection||a.noop).call(b.element)),clearTimeout(b.onChangeTimeout),b.currentValue=d,b.selectedIndex=-1,c.triggerSelectOnValidInput&&b.isExactMatch(e)?void b.select(0):void(e.lengthh&&(c.suggestions=c.suggestions.slice(0,h)),c},getSuggestions:function(b){var c,d,e,f,g=this,h=g.options,i=h.serviceUrl;if(h.params[h.paramName]=b,h.onSearchStart.call(g.element,h.params)!==!1){if(d=h.ignoreParams?null:h.params,a.isFunction(h.lookup))return void h.lookup(b,function(a){g.suggestions=a.suggestions,g.suggest(),h.onSearchComplete.call(g.element,b,a.suggestions)});g.isLocal?c=g.getSuggestionsLocal(b):(a.isFunction(i)&&(i=i.call(g.element,b)),e=i+"?"+a.param(d||{}),c=g.cachedResponse[e]),c&&a.isArray(c.suggestions)?(g.suggestions=c.suggestions,g.suggest(),h.onSearchComplete.call(g.element,b,c.suggestions)):g.isBadQuery(b)?h.onSearchComplete.call(g.element,b,[]):(g.abortAjax(),f={url:i,data:d,type:h.type,dataType:h.dataType},a.extend(f,h.ajaxSettings),g.currentRequest=a.ajax(f).done(function(a){var c;g.currentRequest=null,c=h.transformResult(a,b),g.processResponse(c,b,e),h.onSearchComplete.call(g.element,b,c.suggestions)}).fail(function(a,c,d){h.onSearchError.call(g.element,b,a,c,d)}))}},isBadQuery:function(a){if(!this.options.preventBadQueries)return!1;for(var b=this.badQueries,c=b.length;c--;)if(0===a.indexOf(b[c]))return!0;return!1},hide:function(){var b=this,c=a(b.suggestionsContainer);a.isFunction(b.options.onHide)&&b.visible&&b.options.onHide.call(b.element,c),b.visible=!1,b.selectedIndex=-1,clearTimeout(b.onChangeTimeout),a(b.suggestionsContainer).hide(),b.signalHint(null)},suggest:function(){if(!this.suggestions.length)return void(this.options.showNoSuggestionNotice?this.noSuggestions():this.hide());var b,c=this,d=c.options,e=d.groupBy,f=d.formatResult,g=c.getQuery(c.currentValue),h=c.classes.suggestion,i=c.classes.selected,j=a(c.suggestionsContainer),k=a(c.noSuggestionsContainer),l=d.beforeRender,m="",n=function(a,c){var f=a.data[e];return b===f?"":(b=f,d.formatGroup(a,b))};return d.triggerSelectOnValidInput&&c.isExactMatch(g)?void c.select(0):(a.each(c.suggestions,function(a,b){e&&(m+=n(b,g,a)),m+=''+f(b,g,a)+"
"}),this.adjustContainerWidth(),k.detach(),j.html(m),a.isFunction(l)&&l.call(c.element,j,c.suggestions),c.fixPosition(),j.show(),d.autoSelectFirst&&(c.selectedIndex=0,j.scrollTop(0),j.children("."+h).first().addClass(i)),c.visible=!0,void c.findBestHint())},noSuggestions:function(){var b=this,c=b.options.beforeRender,d=a(b.suggestionsContainer),e=a(b.noSuggestionsContainer);this.adjustContainerWidth(),e.detach(),d.empty(),d.append(e),a.isFunction(c)&&c.call(b.element,d,b.suggestions),b.fixPosition(),d.show(),b.visible=!0},adjustContainerWidth:function(){var b,c=this,d=c.options,e=a(c.suggestionsContainer);"auto"===d.width?(b=c.el.outerWidth(),e.css("width",b>0?b:300)):"flex"===d.width&&e.css("width","")},findBestHint:function(){var b=this,c=b.el.val().toLowerCase(),d=null;c&&(a.each(b.suggestions,function(a,b){var e=0===b.value.toLowerCase().indexOf(c);return e&&(d=b),!e}),b.signalHint(d))},signalHint:function(b){var c="",d=this;b&&(c=d.currentValue+b.value.substr(d.currentValue.length)),d.hintValue!==c&&(d.hintValue=c,d.hint=b,(this.options.onHint||a.noop)(c))},verifySuggestionsFormat:function(b){return b.length&&"string"==typeof b[0]?a.map(b,function(a){return{value:a,data:null}}):b},validateOrientation:function(b,c){return b=a.trim(b||"").toLowerCase(),-1===a.inArray(b,["auto","bottom","top"])&&(b=c),b},processResponse:function(a,b,c){var d=this,e=d.options;a.suggestions=d.verifySuggestionsFormat(a.suggestions),e.noCache||(d.cachedResponse[c]=a,e.preventBadQueries&&!a.suggestions.length&&d.badQueries.push(b)),b===d.getQuery(d.currentValue)&&(d.suggestions=a.suggestions,d.suggest())},activate:function(b){var c,d=this,e=d.classes.selected,f=a(d.suggestionsContainer),g=f.find("."+d.classes.suggestion);return f.find("."+e).removeClass(e),d.selectedIndex=b,-1!==d.selectedIndex&&g.length>d.selectedIndex?(c=g.get(d.selectedIndex),a(c).addClass(e),c):null},selectHint:function(){var b=this,c=a.inArray(b.hint,b.suggestions);b.select(c)},select:function(a){var b=this;b.hide(),b.onSelect(a)},moveUp:function(){var b=this;if(-1!==b.selectedIndex)return 0===b.selectedIndex?(a(b.suggestionsContainer).children().first().removeClass(b.classes.selected),b.selectedIndex=-1,b.el.val(b.currentValue),void b.findBestHint()):void b.adjustScroll(b.selectedIndex-1)},moveDown:function(){var a=this;a.selectedIndex!==a.suggestions.length-1&&a.adjustScroll(a.selectedIndex+1)},adjustScroll:function(b){var c=this,d=c.activate(b);if(d){var e,f,g,h=a(d).outerHeight();e=d.offsetTop,f=a(c.suggestionsContainer).scrollTop(),g=f+c.options.maxHeight-h,f>e?a(c.suggestionsContainer).scrollTop(e):e>g&&a(c.suggestionsContainer).scrollTop(e-c.options.maxHeight+h),c.options.preserveInput||c.el.val(c.getValue(c.suggestions[b].value)),c.signalHint(null)}},onSelect:function(b){var c=this,d=c.options.onSelect,e=c.suggestions[b];c.currentValue=c.getValue(e.value),c.currentValue===c.el.val()||c.options.preserveInput||c.el.val(c.currentValue),c.signalHint(null),c.suggestions=[],c.selection=e,a.isFunction(d)&&d.call(c.element,e)},getValue:function(a){var b,c,d=this,e=d.options.delimiter;return e?(b=d.currentValue,c=b.split(e),1===c.length?a:b.substr(0,b.length-c[c.length-1].length)+a):a},dispose:function(){var b=this;b.el.off(".autocomplete").removeData("autocomplete"),a(window).off("resize.autocomplete",b.fixPositionCapture),a(b.suggestionsContainer).remove()}},a.fn.devbridgeAutocomplete=function(c,d){var e="autocomplete";return arguments.length?this.each(function(){var f=a(this),g=f.data(e);"string"==typeof c?g&&"function"==typeof g[c]&&g[c](d):(g&&g.dispose&&g.dispose(),g=new b(this,c),f.data(e,g))}):this.first().data(e)},a.fn.autocomplete||(a.fn.autocomplete=a.fn.devbridgeAutocomplete)});
\ No newline at end of file
diff --git a/source/javascripts/lunr.min.js b/source/javascripts/lunr.min.js
deleted file mode 100644
index 884d1f2a8..000000000
--- a/source/javascripts/lunr.min.js
+++ /dev/null
@@ -1,7 +0,0 @@
-/**
- * lunr - http://lunrjs.com - A bit like Solr, but much smaller and not as bright - 0.7.0
- * Copyright (C) 2016 Oliver Nightingale
- * MIT Licensed
- * @license
- */
-!function(){var t=function(e){var n=new t.Index;return n.pipeline.add(t.trimmer,t.stopWordFilter,t.stemmer),e&&e.call(n,n),n};t.version="0.7.0",t.utils={},t.utils.warn=function(t){return function(e){t.console&&console.warn&&console.warn(e)}}(this),t.utils.asString=function(t){return void 0===t||null===t?"":t.toString()},t.EventEmitter=function(){this.events={}},t.EventEmitter.prototype.addListener=function(){var t=Array.prototype.slice.call(arguments),e=t.pop(),n=t;if("function"!=typeof e)throw new TypeError("last argument must be a function");n.forEach(function(t){this.hasHandler(t)||(this.events[t]=[]),this.events[t].push(e)},this)},t.EventEmitter.prototype.removeListener=function(t,e){if(this.hasHandler(t)){var n=this.events[t].indexOf(e);this.events[t].splice(n,1),this.events[t].length||delete this.events[t]}},t.EventEmitter.prototype.emit=function(t){if(this.hasHandler(t)){var e=Array.prototype.slice.call(arguments,1);this.events[t].forEach(function(t){t.apply(void 0,e)})}},t.EventEmitter.prototype.hasHandler=function(t){return t in this.events},t.tokenizer=function(e){return arguments.length&&null!=e&&void 0!=e?Array.isArray(e)?e.map(function(e){return t.utils.asString(e).toLowerCase()}):e.toString().trim().toLowerCase().split(t.tokenizer.seperator):[]},t.tokenizer.seperator=/[\s\-]+/,t.tokenizer.load=function(t){var e=this.registeredFunctions[t];if(!e)throw new Error("Cannot load un-registered function: "+t);return e},t.tokenizer.label="default",t.tokenizer.registeredFunctions={"default":t.tokenizer},t.tokenizer.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing tokenizer: "+n),e.label=n,this.registeredFunctions[n]=e},t.Pipeline=function(){this._stack=[]},t.Pipeline.registeredFunctions={},t.Pipeline.registerFunction=function(e,n){n in this.registeredFunctions&&t.utils.warn("Overwriting existing registered function: "+n),e.label=n,t.Pipeline.registeredFunctions[e.label]=e},t.Pipeline.warnIfFunctionNotRegistered=function(e){var n=e.label&&e.label in this.registeredFunctions;n||t.utils.warn("Function is not registered with pipeline. This may cause problems when serialising the index.\n",e)},t.Pipeline.load=function(e){var n=new t.Pipeline;return e.forEach(function(e){var i=t.Pipeline.registeredFunctions[e];if(!i)throw new Error("Cannot load un-registered function: "+e);n.add(i)}),n},t.Pipeline.prototype.add=function(){var e=Array.prototype.slice.call(arguments);e.forEach(function(e){t.Pipeline.warnIfFunctionNotRegistered(e),this._stack.push(e)},this)},t.Pipeline.prototype.after=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");i+=1,this._stack.splice(i,0,n)},t.Pipeline.prototype.before=function(e,n){t.Pipeline.warnIfFunctionNotRegistered(n);var i=this._stack.indexOf(e);if(-1==i)throw new Error("Cannot find existingFn");this._stack.splice(i,0,n)},t.Pipeline.prototype.remove=function(t){var e=this._stack.indexOf(t);-1!=e&&this._stack.splice(e,1)},t.Pipeline.prototype.run=function(t){for(var e=[],n=t.length,i=this._stack.length,r=0;n>r;r++){for(var o=t[r],s=0;i>s&&(o=this._stack[s](o,r,t),void 0!==o&&""!==o);s++);void 0!==o&&""!==o&&e.push(o)}return e},t.Pipeline.prototype.reset=function(){this._stack=[]},t.Pipeline.prototype.toJSON=function(){return this._stack.map(function(e){return t.Pipeline.warnIfFunctionNotRegistered(e),e.label})},t.Vector=function(){this._magnitude=null,this.list=void 0,this.length=0},t.Vector.Node=function(t,e,n){this.idx=t,this.val=e,this.next=n},t.Vector.prototype.insert=function(e,n){this._magnitude=void 0;var i=this.list;if(!i)return this.list=new t.Vector.Node(e,n,i),this.length++;if(en.idx?n=n.next:(i+=e.val*n.val,e=e.next,n=n.next);return i},t.Vector.prototype.similarity=function(t){return this.dot(t)/(this.magnitude()*t.magnitude())},t.SortedSet=function(){this.length=0,this.elements=[]},t.SortedSet.load=function(t){var e=new this;return e.elements=t,e.length=t.length,e},t.SortedSet.prototype.add=function(){var t,e;for(t=0;t1;){if(o===t)return r;t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r]}return o===t?r:-1},t.SortedSet.prototype.locationFor=function(t){for(var e=0,n=this.elements.length,i=n-e,r=e+Math.floor(i/2),o=this.elements[r];i>1;)t>o&&(e=r),o>t&&(n=r),i=n-e,r=e+Math.floor(i/2),o=this.elements[r];return o>t?r:t>o?r+1:void 0},t.SortedSet.prototype.intersect=function(e){for(var n=new t.SortedSet,i=0,r=0,o=this.length,s=e.length,a=this.elements,h=e.elements;;){if(i>o-1||r>s-1)break;a[i]!==h[r]?a[i]h[r]&&r++:(n.add(a[i]),i++,r++)}return n},t.SortedSet.prototype.clone=function(){var e=new t.SortedSet;return e.elements=this.toArray(),e.length=e.elements.length,e},t.SortedSet.prototype.union=function(t){var e,n,i;this.length>=t.length?(e=this,n=t):(e=t,n=this),i=e.clone();for(var r=0,o=n.toArray();rp;p++)c[p]===a&&d++;h+=d/f*l.boost}}this.tokenStore.add(a,{ref:o,tf:h})}n&&this.eventEmitter.emit("add",e,this)},t.Index.prototype.remove=function(t,e){var n=t[this._ref],e=void 0===e?!0:e;if(this.documentStore.has(n)){var i=this.documentStore.get(n);this.documentStore.remove(n),i.forEach(function(t){this.tokenStore.remove(t,n)},this),e&&this.eventEmitter.emit("remove",t,this)}},t.Index.prototype.update=function(t,e){var e=void 0===e?!0:e;this.remove(t,!1),this.add(t,!1),e&&this.eventEmitter.emit("update",t,this)},t.Index.prototype.idf=function(t){var e="@"+t;if(Object.prototype.hasOwnProperty.call(this._idfCache,e))return this._idfCache[e];var n=this.tokenStore.count(t),i=1;return n>0&&(i=1+Math.log(this.documentStore.length/n)),this._idfCache[e]=i},t.Index.prototype.search=function(e){var n=this.pipeline.run(this.tokenizerFn(e)),i=new t.Vector,r=[],o=this._fields.reduce(function(t,e){return t+e.boost},0),s=n.some(function(t){return this.tokenStore.has(t)},this);if(!s)return[];n.forEach(function(e,n,s){var a=1/s.length*this._fields.length*o,h=this,u=this.tokenStore.expand(e).reduce(function(n,r){var o=h.corpusTokens.indexOf(r),s=h.idf(r),u=1,l=new t.SortedSet;if(r!==e){var c=Math.max(3,r.length-e.length);u=1/Math.log(c)}o>-1&&i.insert(o,a*s*u);for(var f=h.tokenStore.get(r),d=Object.keys(f),p=d.length,v=0;p>v;v++)l.add(f[d[v]].ref);return n.union(l)},new t.SortedSet);r.push(u)},this);var a=r.reduce(function(t,e){return t.intersect(e)});return a.map(function(t){return{ref:t,score:i.similarity(this.documentVector(t))}},this).sort(function(t,e){return e.score-t.score})},t.Index.prototype.documentVector=function(e){for(var n=this.documentStore.get(e),i=n.length,r=new t.Vector,o=0;i>o;o++){var s=n.elements[o],a=this.tokenStore.get(s)[e].tf,h=this.idf(s);r.insert(this.corpusTokens.indexOf(s),a*h)}return r},t.Index.prototype.toJSON=function(){return{version:t.version,fields:this._fields,ref:this._ref,tokenizer:this.tokenizerFn.label,documentStore:this.documentStore.toJSON(),tokenStore:this.tokenStore.toJSON(),corpusTokens:this.corpusTokens.toJSON(),pipeline:this.pipeline.toJSON()}},t.Index.prototype.use=function(t){var e=Array.prototype.slice.call(arguments,1);e.unshift(this),t.apply(this,e)},t.Store=function(){this.store={},this.length=0},t.Store.load=function(e){var n=new this;return n.length=e.length,n.store=Object.keys(e.store).reduce(function(n,i){return n[i]=t.SortedSet.load(e.store[i]),n},{}),n},t.Store.prototype.set=function(t,e){this.has(t)||this.length++,this.store[t]=e},t.Store.prototype.get=function(t){return this.store[t]},t.Store.prototype.has=function(t){return t in this.store},t.Store.prototype.remove=function(t){this.has(t)&&(delete this.store[t],this.length--)},t.Store.prototype.toJSON=function(){return{store:this.store,length:this.length}},t.stemmer=function(){var t={ational:"ate",tional:"tion",enci:"ence",anci:"ance",izer:"ize",bli:"ble",alli:"al",entli:"ent",eli:"e",ousli:"ous",ization:"ize",ation:"ate",ator:"ate",alism:"al",iveness:"ive",fulness:"ful",ousness:"ous",aliti:"al",iviti:"ive",biliti:"ble",logi:"log"},e={icate:"ic",ative:"",alize:"al",iciti:"ic",ical:"ic",ful:"",ness:""},n="[^aeiou]",i="[aeiouy]",r=n+"[^aeiouy]*",o=i+"[aeiou]*",s="^("+r+")?"+o+r,a="^("+r+")?"+o+r+"("+o+")?$",h="^("+r+")?"+o+r+o+r,u="^("+r+")?"+i,l=new RegExp(s),c=new RegExp(h),f=new RegExp(a),d=new RegExp(u),p=/^(.+?)(ss|i)es$/,v=/^(.+?)([^s])s$/,g=/^(.+?)eed$/,m=/^(.+?)(ed|ing)$/,y=/.$/,S=/(at|bl|iz)$/,w=new RegExp("([^aeiouylsz])\\1$"),k=new RegExp("^"+r+i+"[^aeiouwxy]$"),x=/^(.+?[^aeiou])y$/,b=/^(.+?)(ational|tional|enci|anci|izer|bli|alli|entli|eli|ousli|ization|ation|ator|alism|iveness|fulness|ousness|aliti|iviti|biliti|logi)$/,E=/^(.+?)(icate|ative|alize|iciti|ical|ful|ness)$/,F=/^(.+?)(al|ance|ence|er|ic|able|ible|ant|ement|ment|ent|ou|ism|ate|iti|ous|ive|ize)$/,_=/^(.+?)(s|t)(ion)$/,z=/^(.+?)e$/,O=/ll$/,P=new RegExp("^"+r+i+"[^aeiouwxy]$"),T=function(n){var i,r,o,s,a,h,u;if(n.length<3)return n;if(o=n.substr(0,1),"y"==o&&(n=o.toUpperCase()+n.substr(1)),s=p,a=v,s.test(n)?n=n.replace(s,"$1$2"):a.test(n)&&(n=n.replace(a,"$1$2")),s=g,a=m,s.test(n)){var T=s.exec(n);s=l,s.test(T[1])&&(s=y,n=n.replace(s,""))}else if(a.test(n)){var T=a.exec(n);i=T[1],a=d,a.test(i)&&(n=i,a=S,h=w,u=k,a.test(n)?n+="e":h.test(n)?(s=y,n=n.replace(s,"")):u.test(n)&&(n+="e"))}if(s=x,s.test(n)){var T=s.exec(n);i=T[1],n=i+"i"}if(s=b,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+t[r])}if(s=E,s.test(n)){var T=s.exec(n);i=T[1],r=T[2],s=l,s.test(i)&&(n=i+e[r])}if(s=F,a=_,s.test(n)){var T=s.exec(n);i=T[1],s=c,s.test(i)&&(n=i)}else if(a.test(n)){var T=a.exec(n);i=T[1]+T[2],a=c,a.test(i)&&(n=i)}if(s=z,s.test(n)){var T=s.exec(n);i=T[1],s=c,a=f,h=P,(s.test(i)||a.test(i)&&!h.test(i))&&(n=i)}return s=O,a=c,s.test(n)&&a.test(n)&&(s=y,n=n.replace(s,"")),"y"==o&&(n=o.toLowerCase()+n.substr(1)),n};return T}(),t.Pipeline.registerFunction(t.stemmer,"stemmer"),t.generateStopWordFilter=function(t){var e=t.reduce(function(t,e){return t[e]=e,t},{});return function(t){return t&&e[t]!==t?t:void 0}},t.stopWordFilter=t.generateStopWordFilter(["a","able","about","across","after","all","almost","also","am","among","an","and","any","are","as","at","be","because","been","but","by","can","cannot","could","dear","did","do","does","either","else","ever","every","for","from","get","got","had","has","have","he","her","hers","him","his","how","however","i","if","in","into","is","it","its","just","least","let","like","likely","may","me","might","most","must","my","neither","no","nor","not","of","off","often","on","only","or","other","our","own","rather","said","say","says","she","should","since","so","some","than","that","the","their","them","then","there","these","they","this","tis","to","too","twas","us","wants","was","we","were","what","when","where","which","while","who","whom","why","will","with","would","yet","you","your"]),t.Pipeline.registerFunction(t.stopWordFilter,"stopWordFilter"),t.trimmer=function(t){return t.replace(/^\W+/,"").replace(/\W+$/,"")},t.Pipeline.registerFunction(t.trimmer,"trimmer"),t.TokenStore=function(){this.root={docs:{}},this.length=0},t.TokenStore.load=function(t){var e=new this;return e.root=t.root,e.length=t.length,e},t.TokenStore.prototype.add=function(t,e,n){var n=n||this.root,i=t.charAt(0),r=t.slice(1);return i in n||(n[i]={docs:{}}),0===r.length?(n[i].docs[e.ref]=e,void(this.length+=1)):this.add(r,e,n[i])},t.TokenStore.prototype.has=function(t){if(!t)return!1;for(var e=this.root,n=0;n$1<\/span>')
- .replace('Guides - ', '')
-
- var doc = window.lunrData.docs[suggestion.ref]
- var content = doc.content
-
- content = content.replace(/<[^>]*>/g, '')
- var excerpt = excerptSearch(currentValue, content, {
- padding: 40,
- highlightClass: 'highlighted'
- })
-
- return "" + title + " " + excerpt + "
"
- },
-
- onSelect: function (suggestion) {
- window.location.replace(suggestion.data.url)
- }
- })
- $('#search').attr('readonly', true).autocomplete('disable')
-
-
- // Setup lunr.js
- //
- window.lunrIndex = null;
- window.lunrData = null;
-
- $.ajax({
- url: "/search.json",
- cache: true,
- method: 'GET',
- success: function(data) {
- window.lunrData = data;
- window.lunrIndex = lunr.Index.load(lunrData.index);
- $('#search').attr('readonly', false).autocomplete('enable')
- }
- });
-})
diff --git a/source/layouts/blog.erb b/source/layouts/blog.erb
index ebb98ed64..26da1917f 100644
--- a/source/layouts/blog.erb
+++ b/source/layouts/blog.erb
@@ -25,14 +25,6 @@
<%= article_title(current_page) %>
Posted by <%= article_author(current_page) %> on <%= article_date(current_page) %>
-
-
- Share
-
-
-
- Tweet
-
<%= article_image(current_page) %>
@@ -52,33 +44,8 @@
<%= current_page.body %>
-
-
-
-
- Star
-
-
-
- Like
-
- " title="Share on Twitter" target="_blank" class="btn btn-default-outline">
-
- Tweet
-
-
- HN
- Vote
-
-
- R
- Share
-
-
-
- <%= partial 'mailing_list' %>
diff --git a/source/layouts/guides.erb b/source/layouts/guides.erb
deleted file mode 100644
index cf6fe0195..000000000
--- a/source/layouts/guides.erb
+++ /dev/null
@@ -1,60 +0,0 @@
-
-
-
- <%= partial 'head' %>
- <%= stylesheet_link_tag 'guides' %>
-
-
-
- <%= partial 'navbar' %>
-
-
-
- <%= breadcrumbs(current_page, guides) %>
-
-
-
- <% guides.categories.each do |category| %>
-
- <% category.pages.each do |page| %>
- ><%= guide_title(page) %>
- <% end %>
-
- <% end %>
-
-
-
- <%= guides_edit_article(current_page.source_file) %>
-
- <% guides.categories.each do |category| %>
-
- <%= guide_title(category) %>
-
- <% category.pages.each do |page| %>
-
- <%= link_to(guide_title(page, current_page.data.version), guide_url(category, page, current_page.data.version)) %>
-
- <% end %>
-
-
- <% end %>
-
-
- <% if current_page.data.version == 'head' && !current_page.path.match('upgrade-notes') %>
-
- You're looking at the guides for the upcoming version of Hanami.
-
- Here are the guides for the latest stable version: 1.0
-
- <% end %>
-
- <%= yield %>
-
-
-
- <%= guide_pager(current_page, guides, current_page.data.version) %>
-
-
- <%= partial 'footer' %>
-
-
diff --git a/source/layouts/home.erb b/source/layouts/home.erb
index 5fdc2b2e2..9c464baa6 100644
--- a/source/layouts/home.erb
+++ b/source/layouts/home.erb
@@ -9,111 +9,22 @@
Hanami
-
The web, with simplicity
+
A flexible framework for maintainable Ruby apps
-
-
-
-
-
-
Hanami is a modern web framework for Ruby.
-
-
-
-
-
-
-
-
-
- Fast response times
-
- Hanami is optimized for speed. It returns responses in a matter of milliseconds. Take the full advantage of Content Delivery Networks to make your apps faster.
-
-
-
-
-
-
-
- Full-featured, but lightweight
-
- Use the 100+ features that we offer to build powerful products without compromising memory. Hanami consumes 60% less memory than other full-featured Ruby frameworks.
-
-
-
-
-
-
-
-
-
-
-
-
- Secure by default
-
- Deploy applications that rely on latest browser technologies such as Content Security Policy, X-Frame headers, automatic escaping to protect your users against the most common security threats.
-
-
-
-
-
-
-
- Simple and productive
-
- Enjoy Hanami's simplicity of design and the minimalism of its components. Write flexible code in a matter of minutes, and make it easy to change for the future.
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
Download, Develop, Deploy in 5 minutes.
@@ -129,21 +40,25 @@
-
% gem install hanami
+
+% gem install hanami
Successfully installed hanami-<%= hanami_version %>
-1 gem installed
+3 gems installed
-% hanami new bookshelf --database=postgresql
-19 files successfully created
+% hanami new bookshelf
+Created bookshelf/
+-> Within bookshelf/
+-> # ...
+-> Running Bundler install...
+-> Running NPM install...
+-> Running Hanami install...
-
% cd bookshelf && echo "ruby '2.4.2'" >> Gemfile && bundle
-Bundle complete! 8 Gemfile dependencies, 50 gems now installed.
-
-% git add . && git commit -m "Initial commit"
-[master (root-commit) b6df611] Initial commit
- 38 files changed, 685 insertions(+)
+
+% git init . && git add . && git commit -m "Initial commit"
+[main (root-commit) 629fc96] Initial commit
+33 files changed, 1430 insertions(+)
@@ -151,19 +66,11 @@ Bundle complete! 8 Gemfile dependencies, 50 gems now installed.
Creating app... done, β¬’ Creating cherry-blossom-1234
https://cherry-blossom-1234.herokuapp.com/ | https://git.heroku.com/cherry-blossom-1234.git
-% heroku config:add SERVE_STATIC_ASSETS=true
-Setting SERVE_STATIC_ASSETS and restarting β¬’ cherry-blossom-1234... done, v2
-SERVE_STATIC_ASSETS: true
-
-% git push heroku master
+% git push heroku main
# ...
remote: Verifying deploy... done.
To https://git.heroku.com/cherry-blossom-1234.git
- * [new branch] master -> master
-
-% heroku run bundle exec hanami db migrate
-Running bundle exec hanami db migrate on β¬’ cherry-blossom-1234... up, run.9274 (Free)
-# ...
+ * [new branch] main -> main
% heroku open
Opening cherry-blossom-1234... done
@@ -177,7 +84,7 @@ Opening cherry-blossom-1234... done
@@ -189,7 +96,7 @@ Opening cherry-blossom-1234... done
- <%= partial 'mailing_list' %>
+ <%#= partial 'mailing_list' %>
<%= partial 'footer' %>