├── .env ├── .gitignore ├── README.md ├── archetypes └── default.md ├── bin └── server ├── config.toml ├── content ├── v1.3 │ ├── _index.md │ ├── actions │ │ ├── _index.md │ │ ├── basic-usage.md │ │ ├── control-flow.md │ │ ├── cookies.md │ │ ├── default-template.png │ │ ├── exception-handling.md │ │ ├── exposures.md │ │ ├── http-caching.md │ │ ├── mime-types.md │ │ ├── overview.md │ │ ├── parameters.md │ │ ├── rack-integration.md │ │ ├── request-and-response.md │ │ ├── sessions.md │ │ ├── share-code.md │ │ └── testing.md │ ├── architecture │ │ ├── _index.md │ │ ├── interactors.md │ │ └── overview.md │ ├── assets │ │ ├── _index.md │ │ ├── compressors.md │ │ ├── content-delivery-network.md │ │ ├── overview.md │ │ ├── preprocessors.md │ │ └── use-your-own-assets-management-tool.md │ ├── associations │ │ ├── _index.md │ │ ├── belongs-to.md │ │ ├── has-many-through.md │ │ ├── has-many.md │ │ ├── has-one.md │ │ └── overview.md │ ├── command-line │ │ ├── _index.md │ │ ├── assets.md │ │ ├── database.md │ │ ├── destroy.md │ │ ├── generators.md │ │ ├── plugins.md │ │ ├── project.md │ │ ├── routes.md │ │ └── version.md │ ├── entities │ │ ├── _index.md │ │ ├── custom-schema.md │ │ ├── data-types.md │ │ └── overview.md │ ├── helpers │ │ ├── _index.md │ │ ├── assets.md │ │ ├── custom-helpers.md │ │ ├── escape.md │ │ ├── forms.md │ │ ├── html5.md │ │ ├── links.md │ │ ├── numbers.md │ │ ├── overview.md │ │ └── routing.md │ ├── introduction │ │ ├── _index.md │ │ ├── getting-started.md │ │ └── welcome-page.png │ ├── mailers │ │ ├── _index.md │ │ ├── basic-usage.md │ │ ├── delivery.md │ │ ├── overview.md │ │ ├── share-code.md │ │ ├── templates.md │ │ └── testing.md │ ├── migrations │ │ ├── _index.md │ │ ├── alter-table.md │ │ ├── create-table.md │ │ └── overview.md │ ├── models │ │ ├── _index.md │ │ ├── database-configuration.md │ │ ├── overview.md │ │ └── use-your-own-orm.md │ ├── projects │ │ ├── _index.md │ │ ├── code-reloading.md │ │ ├── http2-early-hints.md │ │ ├── initializers.md │ │ ├── logging.md │ │ ├── rack-middleware.md │ │ ├── rake.md │ │ ├── security.md │ │ └── selectively-boot-apps.md │ ├── repositories │ │ ├── _index.md │ │ ├── overview.md │ │ ├── postgresql.md │ │ └── sql-queries.md │ ├── routing │ │ ├── _index.md │ │ ├── basic-usage.md │ │ ├── overview.md │ │ ├── restful-resources.md │ │ └── testing.md │ ├── upgrade-notes │ │ ├── _index.md │ │ ├── v060.md │ │ ├── v070.md │ │ ├── v080.md │ │ ├── v090.md │ │ ├── v100.md │ │ ├── v110.md │ │ ├── v120.md │ │ └── v130.md │ ├── validations │ │ ├── _index.md │ │ ├── advanced-usage.md │ │ ├── boolean-logic.md │ │ ├── custom-predicates.md │ │ └── overview.md │ └── views │ │ ├── _index.md │ │ ├── basic-usage.md │ │ ├── custom-error-pages.md │ │ ├── layouts.md │ │ ├── mime-types.md │ │ ├── overview.md │ │ ├── share-code.md │ │ ├── templates.md │ │ └── testing.md ├── v2.0 │ ├── _index.md │ ├── actions │ │ ├── 404-response.png │ │ ├── _index.md │ │ ├── control-flow.md │ │ ├── cookies.md │ │ ├── default-error-response.png │ │ ├── exception-handling.md │ │ ├── formats-and-mime-types.md │ │ ├── http-caching.md │ │ ├── inheritance.md │ │ ├── overview.md │ │ ├── parameters.md │ │ ├── rack-integration.md │ │ ├── request-and-response.md │ │ ├── sessions.md │ │ ├── status-codes.md │ │ └── testing.md │ ├── app │ │ ├── _index.md │ │ ├── app-config.md │ │ ├── autoloading.md │ │ ├── booting.md │ │ ├── code-reloading.md │ │ ├── container-and-components.md │ │ ├── environments.md │ │ ├── inflector.md │ │ ├── providers.md │ │ ├── settings.md │ │ └── slices.md │ ├── cli-commands │ │ ├── _index.md │ │ └── commands.md │ ├── introduction │ │ ├── _index.md │ │ ├── getting-started.md │ │ └── hello-from-hanami.png │ ├── logger │ │ ├── _index.md │ │ ├── configuration.md │ │ └── usage.md │ ├── routing │ │ ├── _index.md │ │ └── overview.md │ └── views │ │ ├── _index.md │ │ └── planned_for_2_1.md ├── v2.1 │ ├── _index.md │ ├── actions │ │ ├── 404-response.png │ │ ├── _index.md │ │ ├── control-flow.md │ │ ├── cookies.md │ │ ├── default-error-response.png │ │ ├── exception-handling.md │ │ ├── formats-and-mime-types.md │ │ ├── http-caching.md │ │ ├── inheritance.md │ │ ├── overview.md │ │ ├── parameters.md │ │ ├── rack-integration.md │ │ ├── rendering-views.md │ │ ├── request-and-response.md │ │ ├── sessions.md │ │ ├── status-codes.md │ │ └── testing.md │ ├── app │ │ ├── _index.md │ │ ├── app-config.md │ │ ├── autoloading.md │ │ ├── booting.md │ │ ├── code-reloading.md │ │ ├── container-and-components.md │ │ ├── environments.md │ │ ├── inflector.md │ │ ├── providers.md │ │ ├── settings.md │ │ └── slices.md │ ├── assets │ │ ├── _index.md │ │ ├── customization.md │ │ ├── overview.md │ │ └── using-a-cdn.md │ ├── cli-commands │ │ ├── _index.md │ │ ├── assets.md │ │ ├── commands.md │ │ ├── console.md │ │ ├── dev.md │ │ ├── generate.md │ │ ├── install.md │ │ ├── middleware.md │ │ ├── new.md │ │ ├── routes.md │ │ ├── server.md │ │ └── version.md │ ├── helpers │ │ ├── _index.md │ │ ├── assets.md │ │ ├── html.md │ │ ├── number-formatting.md │ │ ├── overview.md │ │ └── string-escaping.md │ ├── introduction │ │ ├── _index.md │ │ ├── building-a-web-app.md │ │ ├── building-an-api.md │ │ ├── getting-started.md │ │ └── hanami-welcome.png │ ├── logger │ │ ├── _index.md │ │ ├── configuration.md │ │ └── usage.md │ ├── routing │ │ ├── _index.md │ │ └── overview.md │ ├── upgrade-notes │ │ ├── _index.md │ │ └── v2.1.0.md │ └── views │ │ ├── _index.md │ │ ├── configuration.md │ │ ├── context.md │ │ ├── helpers.md │ │ ├── input-and-exposures.md │ │ ├── overview.md │ │ ├── parts.md │ │ ├── rendering-errors.md │ │ ├── rendering-from-actions.md │ │ ├── scopes.md │ │ ├── templates-and-partials.md │ │ ├── testing.md │ │ ├── welcome-to-bookshelf.png │ │ └── working-with-dependencies.md └── v2.2 │ ├── _index.md │ ├── actions │ ├── 404-response.png │ ├── _index.md │ ├── control-flow.md │ ├── cookies.md │ ├── default-error-response.png │ ├── exception-handling.md │ ├── formats-and-mime-types.md │ ├── http-caching.md │ ├── inheritance.md │ ├── overview.md │ ├── parameters.md │ ├── rack-integration.md │ ├── rendering-views.md │ ├── request-and-response.md │ ├── sessions.md │ ├── status-codes.md │ └── testing.md │ ├── app │ ├── _index.md │ ├── app-config.md │ ├── autoloading.md │ ├── booting.md │ ├── code-reloading.md │ ├── container-and-components.md │ ├── environments.md │ ├── inflector.md │ ├── providers.md │ ├── settings.md │ └── slices.md │ ├── assets │ ├── _index.md │ ├── customization.md │ ├── overview.md │ └── using-a-cdn.md │ ├── cli-commands │ ├── _index.md │ ├── assets.md │ ├── commands.md │ ├── console.md │ ├── db.md │ ├── dev.md │ ├── generate.md │ ├── install.md │ ├── middleware.md │ ├── new.md │ ├── routes.md │ ├── server.md │ └── version.md │ ├── database │ ├── _index.md │ ├── configuration.md │ ├── migrations.md │ ├── overview.md │ └── relations.md │ ├── helpers │ ├── _index.md │ ├── assets.md │ ├── html.md │ ├── number-formatting.md │ ├── overview.md │ └── string-escaping.md │ ├── introduction │ ├── _index.md │ ├── building-a-web-app.md │ ├── building-an-api.md │ ├── getting-started.md │ └── hanami-welcome.png │ ├── logger │ ├── _index.md │ ├── configuration.md │ └── usage.md │ ├── operations │ ├── _index.md │ └── overview.md │ ├── routing │ ├── _index.md │ └── overview.md │ ├── upgrade-notes │ ├── _index.md │ ├── v2.1.md │ └── v2.2.md │ └── views │ ├── _index.md │ ├── configuration.md │ ├── context.md │ ├── helpers.md │ ├── input-and-exposures.md │ ├── overview.md │ ├── parts.md │ ├── rendering-errors.md │ ├── rendering-from-actions.md │ ├── scopes.md │ ├── templates-and-partials.md │ ├── testing.md │ ├── welcome-to-bookshelf.png │ └── working-with-dependencies.md ├── netlify.toml └── themes └── hanami ├── LICENSE ├── archetypes └── default.md ├── layouts ├── 404.html ├── _default │ ├── baseof.html │ ├── list.html │ └── single.html ├── index.html ├── partials │ ├── footer.html │ ├── head.html │ └── header.html └── shortcodes │ ├── many-to-many.html │ ├── many-to-one.html │ └── one-to-many.html ├── static └── assets │ ├── css │ ├── argon.css │ ├── argon.min.css │ ├── docs.min.css │ ├── syntax.css │ └── theme.css │ ├── img │ ├── brand │ │ ├── favicon.ico │ │ ├── hanami-guides-social.png │ │ ├── purple.png │ │ └── white.png │ ├── icons │ │ └── common │ │ │ ├── github.svg │ │ │ └── google.svg │ └── theme │ │ └── landing.png │ ├── js │ ├── argon.js │ ├── argon.min.js │ └── theme.js │ ├── scss │ ├── argon.scss │ ├── bootstrap │ │ ├── _alert.scss │ │ ├── _badge.scss │ │ ├── _breadcrumb.scss │ │ ├── _button-group.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _carousel.scss │ │ ├── _close.scss │ │ ├── _code.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _grid.scss │ │ ├── _images.scss │ │ ├── _input-group.scss │ │ ├── _jumbotron.scss │ │ ├── _list-group.scss │ │ ├── _media.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _print.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _root.scss │ │ ├── _tables.scss │ │ ├── _tooltip.scss │ │ ├── _transitions.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ ├── mixins │ │ │ ├── _alert.scss │ │ │ ├── _background-variant.scss │ │ │ ├── _badge.scss │ │ │ ├── _border-radius.scss │ │ │ ├── _box-shadow.scss │ │ │ ├── _breakpoints.scss │ │ │ ├── _buttons.scss │ │ │ ├── _caret.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _float.scss │ │ │ ├── _forms.scss │ │ │ ├── _gradients.scss │ │ │ ├── _grid-framework.scss │ │ │ ├── _grid.scss │ │ │ ├── _hover.scss │ │ │ ├── _image.scss │ │ │ ├── _list-group.scss │ │ │ ├── _lists.scss │ │ │ ├── _nav-divider.scss │ │ │ ├── _pagination.scss │ │ │ ├── _reset-text.scss │ │ │ ├── _resize.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _size.scss │ │ │ ├── _table-row.scss │ │ │ ├── _text-emphasis.scss │ │ │ ├── _text-hide.scss │ │ │ ├── _text-truncate.scss │ │ │ ├── _transition.scss │ │ │ └── _visibility.scss │ │ └── utilities │ │ │ ├── _align.scss │ │ │ ├── _background.scss │ │ │ ├── _borders.scss │ │ │ ├── _clearfix.scss │ │ │ ├── _display.scss │ │ │ ├── _embed.scss │ │ │ ├── _flex.scss │ │ │ ├── _float.scss │ │ │ ├── _position.scss │ │ │ ├── _screenreaders.scss │ │ │ ├── _shadows.scss │ │ │ ├── _sizing.scss │ │ │ ├── _spacing.scss │ │ │ ├── _text.scss │ │ │ └── _visibility.scss │ └── custom │ │ ├── _accordion.scss │ │ ├── _alerts.scss │ │ ├── _avatars.scss │ │ ├── _badge.scss │ │ ├── _buttons.scss │ │ ├── _card.scss │ │ ├── _carousel.scss │ │ ├── _close.scss │ │ ├── _custom-forms.scss │ │ ├── _dropdown.scss │ │ ├── _footer.scss │ │ ├── _forms.scss │ │ ├── _functions.scss │ │ ├── _global.scss │ │ ├── _grid.scss │ │ ├── _icons.scss │ │ ├── _input-group.scss │ │ ├── _list-group.scss │ │ ├── _mixins.scss │ │ ├── _modal.scss │ │ ├── _nav.scss │ │ ├── _navbar.scss │ │ ├── _pagination.scss │ │ ├── _popover.scss │ │ ├── _progress.scss │ │ ├── _reboot.scss │ │ ├── _section.scss │ │ ├── _separator.scss │ │ ├── _type.scss │ │ ├── _utilities.scss │ │ ├── _variables.scss │ │ ├── mixins │ │ ├── _alert.scss │ │ ├── _background-variant.scss │ │ ├── _badge.scss │ │ ├── _buttons.scss │ │ ├── _forms.scss │ │ ├── _icon.scss │ │ ├── _modals.scss │ │ └── _popover.scss │ │ ├── utilities │ │ ├── _backgrounds.scss │ │ ├── _floating.scss │ │ ├── _helper.scss │ │ ├── _position.scss │ │ ├── _shadows.scss │ │ ├── _sizing.scss │ │ ├── _spacing.scss │ │ ├── _text.scss │ │ └── _transform.scss │ │ └── vendor │ │ ├── _bootstrap-datepicker.scss │ │ ├── _headroom.scss │ │ └── _nouislider.scss │ └── vendor │ ├── bootstrap-datepicker │ ├── css │ │ ├── bootstrap-datepicker.css │ │ ├── bootstrap-datepicker.css.map │ │ ├── bootstrap-datepicker.min.css │ │ ├── bootstrap-datepicker.standalone.css │ │ ├── bootstrap-datepicker.standalone.css.map │ │ ├── bootstrap-datepicker.standalone.min.css │ │ ├── bootstrap-datepicker3.css │ │ ├── bootstrap-datepicker3.css.map │ │ ├── bootstrap-datepicker3.min.css │ │ ├── bootstrap-datepicker3.standalone.css │ │ ├── bootstrap-datepicker3.standalone.css.map │ │ └── bootstrap-datepicker3.standalone.min.css │ ├── js │ │ ├── bootstrap-datepicker.js │ │ └── bootstrap-datepicker.min.js │ └── locales │ │ ├── bootstrap-datepicker-en-CA.min.js │ │ ├── bootstrap-datepicker.ar-tn.min.js │ │ ├── bootstrap-datepicker.ar.min.js │ │ ├── bootstrap-datepicker.az.min.js │ │ ├── bootstrap-datepicker.bg.min.js │ │ ├── bootstrap-datepicker.bn.min.js │ │ ├── bootstrap-datepicker.br.min.js │ │ ├── bootstrap-datepicker.bs.min.js │ │ ├── bootstrap-datepicker.ca.min.js │ │ ├── bootstrap-datepicker.cs.min.js │ │ ├── bootstrap-datepicker.cy.min.js │ │ ├── bootstrap-datepicker.da.min.js │ │ ├── bootstrap-datepicker.de.min.js │ │ ├── bootstrap-datepicker.el.min.js │ │ ├── bootstrap-datepicker.en-AU.min.js │ │ ├── bootstrap-datepicker.en-CA.min.js │ │ ├── bootstrap-datepicker.en-GB.min.js │ │ ├── bootstrap-datepicker.en-IE.min.js │ │ ├── bootstrap-datepicker.en-NZ.min.js │ │ ├── bootstrap-datepicker.en-ZA.min.js │ │ ├── bootstrap-datepicker.eo.min.js │ │ ├── bootstrap-datepicker.es.min.js │ │ ├── bootstrap-datepicker.et.min.js │ │ ├── bootstrap-datepicker.eu.min.js │ │ ├── bootstrap-datepicker.fa.min.js │ │ ├── bootstrap-datepicker.fi.min.js │ │ ├── bootstrap-datepicker.fo.min.js │ │ ├── bootstrap-datepicker.fr-CH.min.js │ │ ├── bootstrap-datepicker.fr.min.js │ │ ├── bootstrap-datepicker.gl.min.js │ │ ├── bootstrap-datepicker.he.min.js │ │ ├── bootstrap-datepicker.hi.min.js │ │ ├── bootstrap-datepicker.hr.min.js │ │ ├── bootstrap-datepicker.hu.min.js │ │ ├── bootstrap-datepicker.hy.min.js │ │ ├── bootstrap-datepicker.id.min.js │ │ ├── bootstrap-datepicker.is.min.js │ │ ├── bootstrap-datepicker.it-CH.min.js │ │ ├── bootstrap-datepicker.it.min.js │ │ ├── bootstrap-datepicker.ja.min.js │ │ ├── bootstrap-datepicker.ka.min.js │ │ ├── bootstrap-datepicker.kh.min.js │ │ ├── bootstrap-datepicker.kk.min.js │ │ ├── bootstrap-datepicker.km.min.js │ │ ├── bootstrap-datepicker.ko.min.js │ │ ├── bootstrap-datepicker.kr.min.js │ │ ├── bootstrap-datepicker.lt.min.js │ │ ├── bootstrap-datepicker.lv.min.js │ │ ├── bootstrap-datepicker.me.min.js │ │ ├── bootstrap-datepicker.mk.min.js │ │ ├── bootstrap-datepicker.mn.min.js │ │ ├── bootstrap-datepicker.ms.min.js │ │ ├── bootstrap-datepicker.nl-BE.min.js │ │ ├── bootstrap-datepicker.nl.min.js │ │ ├── bootstrap-datepicker.no.min.js │ │ ├── bootstrap-datepicker.oc.min.js │ │ ├── bootstrap-datepicker.pl.min.js │ │ ├── bootstrap-datepicker.pt-BR.min.js │ │ ├── bootstrap-datepicker.pt.min.js │ │ ├── bootstrap-datepicker.ro.min.js │ │ ├── bootstrap-datepicker.rs-latin.min.js │ │ ├── bootstrap-datepicker.rs.min.js │ │ ├── bootstrap-datepicker.ru.min.js │ │ ├── bootstrap-datepicker.si.min.js │ │ ├── bootstrap-datepicker.sk.min.js │ │ ├── bootstrap-datepicker.sl.min.js │ │ ├── bootstrap-datepicker.sq.min.js │ │ ├── bootstrap-datepicker.sr-latin.min.js │ │ ├── bootstrap-datepicker.sr.min.js │ │ ├── bootstrap-datepicker.sv.min.js │ │ ├── bootstrap-datepicker.sw.min.js │ │ ├── bootstrap-datepicker.ta.min.js │ │ ├── bootstrap-datepicker.tg.min.js │ │ ├── bootstrap-datepicker.th.min.js │ │ ├── bootstrap-datepicker.tk.min.js │ │ ├── bootstrap-datepicker.tr.min.js │ │ ├── bootstrap-datepicker.uk.min.js │ │ ├── bootstrap-datepicker.uz-cyrl.min.js │ │ ├── bootstrap-datepicker.uz-latn.min.js │ │ ├── bootstrap-datepicker.vi.min.js │ │ ├── bootstrap-datepicker.zh-CN.min.js │ │ └── bootstrap-datepicker.zh-TW.min.js │ ├── bootstrap │ ├── bootstrap.bundle.js │ ├── bootstrap.bundle.js.map │ ├── bootstrap.bundle.min.js │ ├── bootstrap.bundle.min.js.map │ ├── bootstrap.js │ ├── bootstrap.js.map │ ├── bootstrap.min.js │ └── bootstrap.min.js.map │ ├── clipboard │ └── clipboard.min.js │ ├── font-awesome │ ├── css │ │ ├── font-awesome.css │ │ └── font-awesome.min.css │ └── fonts │ │ ├── FontAwesome.otf │ │ ├── fontawesome-webfont.eot │ │ ├── fontawesome-webfont.svg │ │ ├── fontawesome-webfont.ttf │ │ ├── fontawesome-webfont.woff │ │ └── fontawesome-webfont.woff2 │ ├── headroom │ └── headroom.min.js │ ├── jquery │ └── jquery.min.js │ ├── nouislider │ ├── css │ │ ├── nouislider.css │ │ └── nouislider.min.css │ └── js │ │ ├── nouislider.js │ │ └── nouislider.min.js │ ├── nucleo │ ├── css │ │ ├── nucleo-svg.css │ │ └── nucleo.css │ └── fonts │ │ ├── nucleo-icons.eot │ │ ├── nucleo-icons.svg │ │ ├── nucleo-icons.ttf │ │ ├── nucleo-icons.woff │ │ └── nucleo-icons.woff2 │ ├── onscreen │ └── onscreen.min.js │ └── popper │ ├── popper.js │ └── popper.min.js └── theme.toml /.env: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | export BRANCH=$(git symbolic-ref HEAD | sed -e 's,.*/\(.*\),\1,') 4 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | .hugo_build.lock 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Hanami Guides 2 | 3 | Learn Hanami with our extensive guides. 4 | 5 | ## Requirements 6 | 7 | * [Git](https://git-scm.com/) (`brew install git`) 8 | * [Hugo](https://gohugo.io/) (`brew install hugo`) 9 | 10 | Hanami Guides are incompatible with Hugo versions above `v0.92.2` for now. 11 | 12 | ## Development 13 | 14 | To run the server in development: 15 | ```sh 16 | bin/server 17 | ``` 18 | 19 | Then visit http://localhost:1313 to see the site. 20 | 21 | ## How to contribute 22 | 23 | 1. Fork the repository. 24 | 1. Create or edit contents. 25 | 1. Open a Pull Request. 26 | 27 | ## Copyright 28 | 29 | Hanami © 2014-2021 Luca Guidi - Released under the [MIT License](https://opensource.org/licenses/MIT). 30 | The contents of this website are released under [Attribution-ShareAlike 4.0 International License (CC BY-SA 4.0)](https://creativecommons.org/licenses/by-sa/4.0/). 31 | -------------------------------------------------------------------------------- /archetypes/default.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "{{ replace .Name "-" " " | title }}" 3 | date: {{ .Date }} 4 | draft: true 5 | --- 6 | 7 | -------------------------------------------------------------------------------- /bin/server: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | set -euo pipefail 3 | IFS=$'\n\t' 4 | 5 | source .env && hugo server -D --disableFastRender 6 | -------------------------------------------------------------------------------- /config.toml: -------------------------------------------------------------------------------- 1 | baseURL = "https://guides.hanamirb.org/" 2 | title = "Hanami Guides" 3 | copyright = "All rights reserved - 2024" 4 | languageCode = "en-us" 5 | theme = "hanami" 6 | googleAnalytics = "UA-47369640-3" 7 | 8 | pygmentscodefences = true 9 | pygmentsuseclasses = false 10 | pygmentsstyle = "monokailight" 11 | 12 | [markup.goldmark.renderer] 13 | unsafe = true 14 | 15 | [permalinks] 16 | posts = "/:slug/" 17 | 18 | [sitemap] 19 | changefreq = "weekly" 20 | filename = "sitemap.xml" 21 | priority = 0.5 22 | 23 | [params] 24 | hanamiversion = "2.2" 25 | description = "Code guides for Hanami Ruby web framework" 26 | facebook = "hanamirb" 27 | twitter = "hanamirb" 28 | instagram = "hanamirb" 29 | github = "hanami/hanami" 30 | keywords = "hanami,hanamirb,hanami guides,documentation,lotus,lotusrb,web,framework,ruby,open source,oss,os,software,free,free software,architecture,fast,lightweight,testing,tdd,bdd,test driven development,behaviour driven development,full stack,mvc,model view object,pattern,patterns,design patterns,oop,object oriented programming,testability,http,https,routing,router,http router,restful,resource,resources,convention,controller,models,repository,query,sql,interactors,two-step view,view,template,presenters,render,rendering,helpers,erb,haml,tilt,json,xml,yaml,yml,framwork,framewrok,riby,free sowftare" 31 | githubrepo = "https://github.com/hanami/guides" 32 | startingpage = "/introduction/getting-started/" 33 | 34 | [security.funcs] 35 | getenv = ['^HUGO_', 'BRANCH'] 36 | -------------------------------------------------------------------------------- /content/v1.3/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: v1.3 3 | --- 4 | -------------------------------------------------------------------------------- /content/v1.3/actions/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Actions 3 | order: 50 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/actions/default-template.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v1.3/actions/default-template.png -------------------------------------------------------------------------------- /content/v1.3/actions/exposures.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Exposures 3 | order: 50 4 | aliases: 5 | - "/actions/exposures" 6 | --- 7 | 8 | For complex use cases we may want to pass data to views in order to present it to our users. 9 | Hanami puts emphasis on explicitness: data isn't shared between the controller action and the view unless we tell it to do so. 10 | 11 | We use a simple and powerful mechanism to achieve our goal: _**exposures**_. 12 | Each exposure first looks for a method matching the given name. 13 | If no method is found, a _getter_ is created with `#attr_reader`. 14 | Only the whitelisted exposures are made available to the corresponding view. 15 | 16 | ```ruby 17 | # apps/web/controllers/dashboard/index.rb 18 | module Web 19 | module Controllers 20 | module Dashboard 21 | class Index 22 | include Web::Action 23 | expose :greeting 24 | 25 | def call(params) 26 | @greeting = "Hello" 27 | @foo = 23 28 | end 29 | end 30 | end 31 | end 32 | end 33 | ``` 34 | 35 | In the example above we have exposed `:greeting`, but not `:foo`. 36 | Only `greeting` can be used from the view and template. 37 | 38 | ```ruby 39 | # apps/web/views/dashboard/index.rb 40 | module Web 41 | module View 42 | module Dashboard 43 | class Index 44 | include Web::View 45 | 46 | def welcome_message 47 | greeting + " and welcome" 48 | end 49 | end 50 | end 51 | end 52 | end 53 | ``` 54 | 55 | If we try to use `foo`, Ruby will raise a `NoMethodError`. 56 | -------------------------------------------------------------------------------- /content/v1.3/architecture/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Architecture 3 | order: 20 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/assets/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assets 3 | order: 150 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/assets/use-your-own-assets-management-tool.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Use Your Own Assets Management 3 | order: 50 4 | aliases: 5 | - "/assets/use-your-own-assets-management" 6 | --- 7 | 8 | Hanami tries to cover basic use cases for assets management: [(pre)compilation](/assets/overview/#compile-mode), [compression](/assets/compressors), [fingerprinting](/assets/overview/#fingerprint-mode), [Content Delivery Network (CDN)](/assets/content-delivery-network) with [Subresource Integrity](/assets/content-delivery-network/#subresource-integrity). 9 | 10 | If it still doesn't fit your needs, you can use your own assets management tool such as Webpack. 11 | 12 | ## Deployment 13 | 14 | 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. 15 | 16 | Please remember that for compatibility with the [Ruby server hosting ecosystem](/projects/rake/#ruby-server-hosting-ecosystem-compatibility), we make available a special Rake task `assets:precompile`, which is run automatically by SaaS vendors. 17 | If this is your situation, you may want override this task in the `Rakefile` of your project, with something more useful for you. 18 | -------------------------------------------------------------------------------- /content/v1.3/associations/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Associations 3 | order: 100 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/command-line/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Command Line 3 | order: 160 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/command-line/project.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Project 3 | order: 10 4 | aliases: 5 | - "/command-line/project" 6 | --- 7 | 8 | ## Project 9 | 10 | We can generate a new project via `hanami new`, followed by the name that we want to use. 11 | 12 | ```shell 13 | $ hanami new bookshelf 14 | ``` 15 | 16 | ## Database 17 | 18 | The default database engine is SQLite. 19 | 20 | We can use the `--database` argument to let Hanami to generate code for a specific database. 21 | 22 | It supports: 23 | 24 | * `postgres` 25 | * `postgresql` 26 | * `sqlite` (default) 27 | * `sqlite3` 28 | * `mysql` 29 | * `mysql2` 30 | 31 | ## Testing Framework 32 | 33 | The default testing framework is RSpec. 34 | 35 | We can use the `--test` argument to specify a different framework, from the list below: 36 | 37 | * `rspec` (default) 38 | * `minitest` 39 | 40 | ## Template Engine 41 | 42 | The default template engine is ERB. 43 | 44 | We can use the `--template` argument to specify a different template engine, from the list below: 45 | 46 | * `erb` (default) 47 | * `haml` 48 | * `slim` 49 | -------------------------------------------------------------------------------- /content/v1.3/command-line/routes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routes 3 | order: 60 4 | aliases: 5 | - "/command-line/routes" 6 | --- 7 | 8 | ## Routes 9 | 10 | In order to print the routes defined by all the applications, use: 11 | 12 | ```shell 13 | $ bundle exec hanami routes 14 | 15 | GET, HEAD / Web::Controllers::Home::Index 16 | books GET, HEAD /books Web::Controllers::Books::Index 17 | new_books GET, HEAD /books/new Web::Controllers::Books::New 18 | books POST /books Web::Controllers::Books::Create 19 | books GET, HEAD /books/:id Web::Controllers::Books::Show 20 | edit_books GET, HEAD /books/:id/edit Web::Controllers::Books::Edit 21 | books PATCH /books/:id Web::Controllers::Books::Update 22 | books DELETE /books/:id Web::Controllers::Books::Destroy 23 | new_account GET, HEAD /account/new Web::Controllers::Account::New 24 | account POST /account Web::Controllers::Account::Create 25 | account GET, HEAD /account Web::Controllers::Account::Show 26 | edit_account GET, HEAD /account/edit Web::Controllers::Account::Edit 27 | account PATCH /account Web::Controllers::Account::Update 28 | account DELETE /account Web::Controllers::Account::Destroy 29 | ``` 30 | -------------------------------------------------------------------------------- /content/v1.3/command-line/version.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Version 3 | order: 70 4 | aliases: 5 | - "/command-line/version" 6 | --- 7 | 8 | ## Version 9 | 10 | By running `hanami version` we can see the current version of the framework that we are using. 11 | 12 | ```shell 13 | $ bundle exec hanami version 14 | v1.3.0 15 | ``` 16 | 17 | There are also `--version` and `-v` aliases. 18 | 19 | ```shell 20 | $ bundle exec hanami --version 21 | v1.3.0 22 | 23 | $ bundle exec hanami -v 24 | v1.3.0 25 | ``` 26 | -------------------------------------------------------------------------------- /content/v1.3/entities/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Entities 3 | order: 90 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/helpers/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Helpers 3 | order: 130 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/helpers/numbers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Numbers 3 | order: 80 4 | aliases: 5 | - "/helpers/numbers" 6 | --- 7 | 8 | Hanami offers a helpful way to present numbers via `#format_number`, a **private method** available only in views. 9 | 10 | ## Usage 11 | 12 | ```ruby 13 | module Web 14 | module Views 15 | module Books 16 | class Show 17 | include Web::View 18 | 19 | def download_count 20 | format_number book.download_count 21 | end 22 | end 23 | end 24 | end 25 | end 26 | ``` 27 | 28 | ```erb 29 | <%= download_count %> 30 | ``` 31 | 32 | ```html 33 | 1,000,000 34 | ``` 35 | 36 | ## Precision 37 | 38 | The default precision is of `2`, but we can specify a different value with the homonym option. 39 | 40 | ```ruby 41 | format_number(Math::PI) # => "3.14" 42 | format_number(Math::PI, precision: 6) # => "3.141592" 43 | ``` 44 | 45 | ## Delimiter 46 | 47 | The default thousands delimiter is `,`. We can use `:delimiter` for a different char. 48 | 49 | ```ruby 50 | format_number(1_000_000) # => "1,000,000" 51 | format_number(1_000_000, delimiter: '.') # => "1.000.000" 52 | ``` 53 | 54 | ## Separator 55 | 56 | The default separator is `.`. We can use `:separator` for a different char. 57 | 58 | ```ruby 59 | format_number(1.23) # => "1.23" 60 | format_number(1.23, separator: ',') # => "1,23" 61 | ``` 62 | -------------------------------------------------------------------------------- /content/v1.3/introduction/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | order: 10 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/introduction/welcome-page.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v1.3/introduction/welcome-page.png -------------------------------------------------------------------------------- /content/v1.3/mailers/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Mailers 3 | order: 140 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/mailers/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | aliases: 5 | - "/mailers/overview" 6 | --- 7 | 8 | A mailer is an object that's responsible to deliver a mail message, by rendering one or more templates. 9 | 10 | For simplicity, each mailer can handle **only one use case (feature)**. 11 | 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. 12 | 13 | ## Example 14 | 15 | Hanami ships a generator that creates a mailer, two templates and the test code. 16 | 17 | ```shell 18 | $ hanami generate mailer welcome 19 | create spec/bookshelf/mailers/welcome_spec.rb 20 | create lib/bookshelf/mailers/welcome.rb 21 | create lib/bookshelf/mailers/templates/welcome.html.erb 22 | create lib/bookshelf/mailers/templates/welcome.txt.erb 23 | ``` 24 | 25 | Let's see how a mailer is structured: 26 | 27 | ```ruby 28 | # lib/bookshelf/mailers/welcome.rb 29 | module Mailers 30 | class Welcome 31 | include Hanami::Mailer 32 | end 33 | end 34 | ``` 35 | 36 |

37 | All the mailers are available under the Mailers namespace. 38 |

39 | 40 | -------------------------------------------------------------------------------- /content/v1.3/mailers/share-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Share Code 3 | order: 50 4 | aliases: 5 | - "/mailers/share-code" 6 | --- 7 | 8 | ## Prepare 9 | 10 | In our settings (`lib/bookshelf.rb`), there is code block that allows to share the code for **all the mailers** of our application. 11 | When a mailer includes the `Hanami::Mailer` module, that block code is yielded within the context of that class. 12 | This is heavily inspired by Ruby Module and its `included` hook. 13 | 14 | Imagine we want to set a default sender for all the mailers. 15 | Instead of specifying it for each mailer, we can use a DRY approach. 16 | 17 | We create a module: 18 | 19 | ```ruby 20 | # lib/mailers/default_sender.rb 21 | module Mailers 22 | module DefaultSender 23 | def self.included(mailer) 24 | mailer.class_eval do 25 | from 'sender@bookshelf.org' 26 | end 27 | end 28 | end 29 | end 30 | ``` 31 | 32 | Then we include in all the mailers of our application, via `prepare`. 33 | 34 | ```ruby 35 | # lib/bookshelf.rb 36 | # ... 37 | 38 | Hanami.configure do 39 | # ... 40 | mailer do 41 | root 'lib/bookshelf/mailers' 42 | 43 | # See https://guides.hanamirb.org/mailers/delivery 44 | delivery :test 45 | 46 | prepare do 47 | include Mailers::DefaultSender 48 | end 49 | end 50 | end 51 | ``` 52 | 53 |

54 | Code included via prepare is available for ALL the mailers of an application. 55 |

56 | 57 | -------------------------------------------------------------------------------- /content/v1.3/mailers/testing.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Testing 3 | order: 60 4 | aliases: 5 | - "/mailers/testing" 6 | --- 7 | 8 | During development and testing we don't want to accidentally send emails to the real world. 9 | The [delivery method](/mailers/delivery) for these two envs is set to `:test`. 10 | 11 | In order to assert that a mailer sent a message, we can look at `Hanami::Mailer.deliveries`. 12 | It's an array of messages that the framework pretended to deliver during a test. 13 | Please make sure to **clear** them in testing setup. 14 | 15 | ```ruby 16 | # spec/bookshelf/mailers/welcome_spec.rb 17 | RSpec.describe Mailers::Welcome do 18 | before { Hanami::Mailer.deliveries.clear } 19 | 20 | let(:user) { ... } 21 | 22 | it "delivers welcome email" do 23 | Mailers::Welcome.deliver(user: user) 24 | mail = Hanami::Mailer.deliveries.last 25 | 26 | expect(mail.to).to eq([user.email]) 27 | expect(mail.body.encoded).to eq("Hello, #{ user.name }") 28 | end 29 | end 30 | ``` 31 | -------------------------------------------------------------------------------- /content/v1.3/migrations/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Migrations 3 | order: 110 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/models/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Models 3 | order: 70 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/models/use-your-own-orm.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Use Your Own ORM 3 | order: 30 4 | aliases: 5 | - "/models/use-your-own-orm" 6 | --- 7 | 8 | Hanami components are decoupled from each other. 9 | This level of separation allows you to use the ORM (data layer) of your choice. 10 | 11 | Here's how to do it: 12 | 13 | 1. Edit your `Gemfile`: 14 | - Remove `hanami-model`. 15 | - Add the gem(s) for your ORM. 16 | 2. Run `bundle install`. 17 | 3. Remove folders that are no longer needed: 18 | - Remove `lib/project_name/entities/` and `lib/projectname/repositories/` 19 | - Remove `spec/project_name/entities/` and `spec/project_name/repositories/`. 20 | 5. Edit `config/environment.rb`: 21 | - Remove `require 'hanami/model'` 22 | - Remove `require_relative '../lib/projectname'` 23 | - Remove `model` block in `Hanami.configure` 24 | 6. Edit `Rakefile`: 25 | - Remove `require 'hanami/rake_tasks'`. 26 | 27 | In general, `lib/project_name/` is a good place to put code that's used across 28 | apps, so we don't recommend getting rid of it entirely. That's also where 29 | Hanami's mailers live. We recommend that you put your new ORM code into that 30 | folder, but you're free to put it elsewhere, and get rid of `lib/` entirely, if 31 | you choose. 32 | 33 | Please be aware that if `hanami-model` is removed from the project features like [database commands](/command-line/database) and [migrations](/migrations/overview) won't be available. 34 | 35 | ## Hanami + ROM 4.0 36 | 37 | If you want to use latest [rom](https://rom-rb.org) version without hanami-model you can use [this repository](https://github.com/solnic/hanami-bookshelf-rom/) as a tutorial for this: 38 | 39 | https://github.com/solnic/hanami-bookshelf-rom/ 40 | -------------------------------------------------------------------------------- /content/v1.3/projects/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Projects 3 | order: 30 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/projects/code-reloading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: "Code Reloading" 3 | order: 10 4 | aliases: 5 | - "/projects/code-reloading" 6 | --- 7 | 8 | _Code reloading_ allows us to edit code and see the changes with a browser refresh, without needing to stop and restart the [server](/command-line/applications). 9 | 10 | ## Development Environment 11 | 12 | This is a development-only feature. 13 | Hanami uses `shotgun` Ruby gem to reload the code as-needed. 14 | New generated projects have this entry in their `Gemfile`: 15 | 16 | ```ruby 17 | group :development do 18 | # Code reloading 19 | # See: https://guides.hanamirb.org/projects/code-reloading 20 | gem 'shotgun' 21 | end 22 | ``` 23 | 24 | Unfortunately, `shotgun` requires that the current environment supports `fork(2)`. 25 | JRuby and Windows don't support it. 26 | 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. 27 | 28 | ## Other Environments 29 | 30 | Hanami doesn't implement _code reloading_ in its core. 31 | 32 | 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. 33 | 34 | Because `shotgun` is only enabled in development, all the other environments don't have this _code reloading_ feature. 35 | 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. 36 | 37 | In other words, once the code is loaded in production, it isn't changed anymore. 38 | -------------------------------------------------------------------------------- /content/v1.3/projects/initializers.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Initializers 3 | order: 40 4 | aliases: 5 | - "/projects/initializers" 6 | --- 7 | 8 | A project can **optionally** have one or more custom initializers. 9 | 10 |

11 | Initializers are optional 12 |

13 | 14 | An initializer is a Ruby file used to setup third-party libraries or some other aspect of the code. 15 | 16 | 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. 17 | 18 | For instance, if we want to setup [Bugsnag](https://bugsnag.com) for our project we can do: 19 | 20 | ```ruby 21 | # config/initializers/bugsnag.rb 22 | require 'bugsnag' 23 | 24 | Bugsnag.configure do |config| 25 | config.api_key = ENV['BUGSNAG_API_KEY'] 26 | end 27 | ``` 28 | 29 |

30 | Project initializers must be added under config/initializers. 31 |

32 | 33 |

34 | Initializers are executed in alphabetical order. 35 |

36 | -------------------------------------------------------------------------------- /content/v1.3/projects/rack-middleware.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rack Middleware 3 | order: 50 4 | aliases: 5 | - "/projects/rack-middleware" 6 | --- 7 | 8 | Hanami exposes a project level [Rack middleware stack](http://www.rubydoc.info/github/rack/rack/master/file/SPEC) to be configured like this: 9 | 10 | ```ruby 11 | # config/environment.rb 12 | Hanami.configure do 13 | middleware.use MyRackMiddleware 14 | end 15 | ``` 16 | 17 | It's worth noticing that this is equivalent to add a middleware in `config.ru` file. 18 | The only difference is that third-party plugins can hook into `Hanami.configure` to inject their own middleware. 19 | -------------------------------------------------------------------------------- /content/v1.3/projects/selectively-boot-apps.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Selectively boot apps 3 | order: 80 4 | aliases: 5 | - "/projects/selectively-boot-apps" 6 | --- 7 | 8 | With Hanami you can build your project by following the [Monolith-First](/architecture/overview/#monolith-first) principle. 9 | As you add more code to the project, you can grow it organically, by splitting the project into several Hanami apps. 10 | 11 | A real world Hanami project could have **dozens of Hanami apps in the same project** (for example, `web` for the front-end, `admin` for the administration, `api` for a JSON API, etc...) 12 | You might want to deploy them to different servers, even though they're all a part of the same project. 13 | For example, most of the servers could be used for the `web` app (for customers on the site), a couple could be used for an `api` (perhaps for customers using mobile apps), and you could have a single server running and `admin` application, since it'll likely get less traffic than the other two. 14 | 15 | We support this, with _selective booting_: 16 | 17 | ```ruby 18 | # config/environment.rb 19 | # ... 20 | Hanami.configure do 21 | if Hanami.app?(:web) 22 | require_relative '../apps/web/application' 23 | mount Web::Application, at: '/' 24 | end 25 | 26 | if Hanami.app?(:api) 27 | require_relative '../apps/api/application' 28 | mount Api::Application, at: '/api' 29 | end 30 | 31 | if Hanami.app?(:admin) 32 | require_relative '../apps/admin/application' 33 | mount Admin::Application, at: '/admin' 34 | end 35 | end 36 | ``` 37 | 38 | You can declare which apps to use with the `HANAMI_APPS` environment variable. 39 | You can provide a single app, or several apps (joined with commas): 40 | 41 | ```shell 42 | $ HANAMI_APPS=web,api bundle exec hanami server 43 | ``` 44 | 45 | This would start only the `web` and `api` applications. 46 | -------------------------------------------------------------------------------- /content/v1.3/repositories/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Repositories 3 | order: 80 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/routing/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routing 3 | order: 40 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/upgrade-notes/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrade Notes 3 | order: 170 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/upgrade-notes/v070.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v0.7.0 3 | order: 20 4 | aliases: 5 | - "/upgrade-notes/v070" 6 | --- 7 | 8 | * Rename all the gems in your `Gemfile` from `lotus` to `hanami` 9 | 10 | * Rename `.lotusrc` into `.hanamirc` 11 | 12 | * Find and replace in project: `lotus` => `hanami` 13 | 14 | * Find and replace in project: `Lotus` => `Hanami` 15 | 16 | * Find and replace in project: `LOTUS` => `HANAMI` 17 | 18 | * Rename the environment variable on your server from `LOTUS_ENV` to `HANAMI_ENV` 19 | 20 | **If you have any problem, don't hesitate to look for help in our [forum](http://discourse.hanamirb.org).** 21 | -------------------------------------------------------------------------------- /content/v1.3/upgrade-notes/v110.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v1.1.0 3 | order: 60 4 | aliases: 5 | - "/upgrade-notes/v110" 6 | --- 7 | 8 | * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 1.1'` 9 | 10 | * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 1.1'` 11 | 12 | * Run `bundle update hanami hanami-model` 13 | 14 | **If you have any problem, don't hesitate to look for help in our [forum](http://discourse.hanamirb.org).** 15 | -------------------------------------------------------------------------------- /content/v1.3/upgrade-notes/v120.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v1.2.0 3 | order: 70 4 | aliases: 5 | - "/upgrade-notes/v120" 6 | --- 7 | 8 | * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 1.2'` 9 | 10 | * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 1.2'` 11 | 12 | * Run `bundle update hanami hanami-model` 13 | 14 | **If you have any problem, don't hesitate to look for help in our [forum](http://discourse.hanamirb.org).** 15 | -------------------------------------------------------------------------------- /content/v1.3/upgrade-notes/v130.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: v1.3.0 3 | order: 80 4 | aliases: 5 | - "/upgrade-notes/v130" 6 | --- 7 | 8 | * Edit `Gemfile`, by changing Hanami version: `gem 'hanami', '~> 1.3'` 9 | 10 | * Edit `Gemfile`, by changing Hanami Model version: `gem 'hanami-model', '~> 1.3'` 11 | 12 | * [DEPRECATION] Remove `force_ssl` from `apps/*/application.rb` in favor of web server rules (e.g. NGINX) or `rack-ssl-enforcer`. 13 | 14 | ```ruby 15 | # config/environment.rb 16 | require "rack/ssl-enforcer" 17 | 18 | Hanami.configure do 19 | # ... 20 | middleware.use Rack::SslEnforcer 21 | end 22 | ``` 23 | 24 | * [DEPRECATION] Remove `body_parsers` from `apps/*/application.rb` in favor of a new Hanami middleware: 25 | 26 | ```ruby 27 | # config/environment.rb 28 | require "hanami/middleware/body_parser" 29 | 30 | Hanami.configure do 31 | # ... 32 | middleware.use Hanami::Middleware::BodyParser, :json 33 | end 34 | ``` 35 | 36 | * [DEPRECATION] Remove usage of `parsed_request_body` from actions. Parsed body is accessible via `params`. 37 | 38 | * [DEPRECATION] Convert `Hanami::Utils::String` usage of instance methods to class methods (e.g. `Hanami::Utils::String.new("hanami").titleize` to `Hanami::Utils::String.titleize("hanami")`) 39 | 40 | * [DEPRECATION] Convert `Hanami::Utils::Hash` usage of instance methods to class methods (e.g. `Hanami::Utils::Hash.new("a" => 1).symbolize` to `Hanami::Utils::Hash.symbolize("a" => 1)`) 41 | 42 | * Run `bundle update hanami hanami-model` 43 | 44 | **If you have any problem, don't hesitate to look for help in our [forum](http://discourse.hanamirb.org).** 45 | -------------------------------------------------------------------------------- /content/v1.3/validations/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Validations 3 | order: 120 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/validations/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | aliases: 5 | - "/validations/overview" 6 | --- 7 | 8 | `Hanami::Validations` is a mixin that, once included by an object, adds lightweight set of validations to it. 9 | 10 | 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 `|`). 11 | 12 | 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`. 13 | 14 | ```ruby 15 | class Signup 16 | include Hanami::Validations 17 | 18 | validations do 19 | required(:name) { filled? & str? & size?(3..64) } 20 | end 21 | end 22 | 23 | result = Signup.new(name: "Luca").validate 24 | result.success? # => true 25 | ``` 26 | 27 | There is more that `Hanami::Validations` can do: **type safety**, **composition**, **complex data structures**, **built-in and custom predicates**. 28 | -------------------------------------------------------------------------------- /content/v1.3/views/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Views 3 | order: 60 4 | --- 5 | -------------------------------------------------------------------------------- /content/v1.3/views/custom-error-pages.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Custom Error Pages 3 | order: 60 4 | aliases: 5 | - "/views/custom-error-pages" 6 | --- 7 | 8 | When an unsuccessful request is returned, there are some special pages that a Hanami application presents to users. 9 | 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. 10 | 11 | Hanami allows us to customize them on a per-application basis. 12 | We just need to create a template with the corresponding HTTP code as the filename (e.g. `apps/web/templates/500.html.erb`). 13 | From then on, all 500 errors (Internal Server Error) will be presented using that template (like for an exception that is not rescued). 14 | 15 |

16 | A template for a custom error page MUST be named after the HTTP code that it targets. 17 | Example: 500.html.erb for Internal Server Error (500). 18 |

19 | 20 |

21 | A template for a custom error page MUST be placed under the templates directory of the application. 22 |

23 | -------------------------------------------------------------------------------- /content/v1.3/views/share-code.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Share Code 3 | order: 70 4 | aliases: 5 | - "/views/share-code" 6 | --- 7 | 8 | ## Prepare 9 | 10 | 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. 11 | When a view includes the `Web::View` module, that block code is yielded within the context of that class. 12 | This is heavily inspired by Ruby Module and its `included` hook. 13 | 14 | Imagine we have an application that only renders JSON. 15 | For each view we should specify the handled format. This can be tedious to do by hand, but we can easily DRY our code. 16 | 17 | We craft a module in `apps/web/views/accept_json.rb`. 18 | 19 | ```ruby 20 | # apps/web/views/accept_json.rb 21 | module Web 22 | module Views 23 | module AcceptJson 24 | def self.included(view) 25 | view.class_eval do 26 | format :json 27 | end 28 | end 29 | end 30 | end 31 | end 32 | ``` 33 | 34 | Then we can load the file and include the module in **all** the views of our application, using view.prepare. 35 | 36 | ```ruby 37 | # apps/web/application.rb 38 | require_relative './views/accept_json' 39 | 40 | module Web 41 | class Application < Hanami::Application 42 | configure do 43 | # ... 44 | view.prepare do 45 | include Web::Views::AcceptJson 46 | end 47 | end 48 | end 49 | end 50 | ``` 51 | 52 |

53 | Code included via prepare is available for ALL the views of an application. 54 |

55 | -------------------------------------------------------------------------------- /content/v2.0/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: v2.0 3 | --- 4 | -------------------------------------------------------------------------------- /content/v2.0/actions/404-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.0/actions/404-response.png -------------------------------------------------------------------------------- /content/v2.0/actions/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Actions 3 | order: 50 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.0/actions/default-error-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.0/actions/default-error-response.png -------------------------------------------------------------------------------- /content/v2.0/actions/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | aliases: 5 | - "/actions/overview" 6 | --- 7 | 8 | ## Actions 9 | 10 | In a Hanami application, actions are responsible for handling HTTP requests. Actions decide what HTTP response your application returns for a given request - its status, body, headers, whether to issue a redirect, and so on. 11 | 12 | Every action in your Hanami application is an individual class. Actions define a `#handle` method which takes two arguments: `request`, an object representing the incoming request, and `response`, an object representing the outgoing response. 13 | 14 | Modifying the response object allows you to control how your application responds to a request. 15 | 16 | ```ruby 17 | # app/actions/home/show.rb 18 | 19 | module Bookshelf 20 | module Actions 21 | module Home 22 | class Show < Bookshelf::Action 23 | def handle(request, response) 24 | name = request.params[:name] 25 | 26 | response.body = "Welcome to Bookshelf #{name}!" 27 | end 28 | end 29 | end 30 | end 31 | end 32 | ``` 33 | 34 | As the code above suggests, the `request` object provides access to the parameters associated with the incoming request through a `#params` method. 35 | 36 | Let's start by taking a look at action [parameters](/v2.0/actions/parameters/). 37 | -------------------------------------------------------------------------------- /content/v2.0/app/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: App 3 | order: 20 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.0/app/code-reloading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Code reloading 3 | order: 90 4 | --- 5 | 6 | Hanami offers fast code reloading in development via the [hanami-reloader](https://github.com/hanami/reloader) gem. 7 | 8 | When you run `hanami server` in development, `guard` watches the file system for code edits and restarts the Hanami server when changes occur. 9 | 10 | Which directories are watched can be configured in the `Guardfile` of your project. 11 | 12 | ```ruby 13 | # Guardfile 14 | 15 | group :server do 16 | guard "puma", port: ENV["HANAMI_PORT"] || 2300 do 17 | watch(%r{config/*}) 18 | watch(%r{lib/*}) 19 | watch(%r{app/*}) 20 | watch(%r{slices/*}) 21 | end 22 | end 23 | ``` 24 | 25 | Hanami takes an "outside the framework" approach to code reloading. This has several advantages: 26 | 27 | - file system watching is delegated to `guard`. 28 | - Hanami internals are free from code reloading awareness. 29 | - if the hanami-reloader gem is not present (which is true in production), code reloading logic is eliminated. 30 | 31 | Thanks to [Zeitwerk](/v2.0/app/autoloading/) and [lazy loading](/v2.0/app/booting/), code reloading is also very fast. 32 | 33 | ### Reloading in the console 34 | 35 | If you have an existing console session and make a code change, you can use your updated code via the `reload` helper: 36 | 37 | ```ruby 38 | bundle exec hanami console 39 | 40 | bookshelf[development]> reload 41 | Reloading... 42 | ``` 43 | -------------------------------------------------------------------------------- /content/v2.0/cli-commands/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CLI commands 3 | order: 15 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.0/introduction/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | order: 10 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.0/introduction/hello-from-hanami.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.0/introduction/hello-from-hanami.png -------------------------------------------------------------------------------- /content/v2.0/logger/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Logger 3 | order: 80 4 | --- 5 | 6 | TBD 7 | -------------------------------------------------------------------------------- /content/v2.0/routing/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routing 3 | order: 40 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.0/views/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Views 3 | order: 90 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.0/views/planned_for_2_1.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Planned for 2.1 3 | order: 10 4 | --- 5 | 6 | Hanami 2.0 does not yet include integrated view rendering. This is planned for the upcoming 2.1 release. 7 | 8 | In the meantime, Hanami 2.0 is well suited for JSON APIs or manual templating with the view engine of your choice through [manually setting `response.body`](/v2.0/actions/request-and-response/#response) in actions. 9 | -------------------------------------------------------------------------------- /content/v2.1/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: v2.1 3 | --- 4 | -------------------------------------------------------------------------------- /content/v2.1/actions/404-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.1/actions/404-response.png -------------------------------------------------------------------------------- /content/v2.1/actions/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Actions 3 | order: 50 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/actions/default-error-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.1/actions/default-error-response.png -------------------------------------------------------------------------------- /content/v2.1/actions/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | aliases: 5 | - "/actions/overview" 6 | --- 7 | 8 | ## Actions 9 | 10 | In a Hanami application, actions are responsible for handling HTTP requests. Actions decide what HTTP response your application returns for a given request - its status, body, headers, whether to issue a redirect, and so on. 11 | 12 | Every action in your Hanami application is an individual class. Actions define a `#handle` method which takes two arguments: `request`, an object representing the incoming request, and `response`, an object representing the outgoing response. 13 | 14 | Modifying the response object allows you to control how your application responds to a request. 15 | 16 | ```ruby 17 | # app/actions/home/show.rb 18 | 19 | module Bookshelf 20 | module Actions 21 | module Home 22 | class Show < Bookshelf::Action 23 | def handle(request, response) 24 | name = request.params[:name] 25 | 26 | response.body = "Welcome to Bookshelf #{name}!" 27 | end 28 | end 29 | end 30 | end 31 | end 32 | ``` 33 | 34 | As the code above suggests, the `request` object provides access to the parameters associated with the incoming request through a `#params` method. 35 | 36 | Let's start by taking a look at action [parameters](/v2.1/actions/parameters/). 37 | -------------------------------------------------------------------------------- /content/v2.1/actions/rendering-views.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rendering views 3 | order: 35 4 | --- 5 | 6 | Hanami actions are designed to work seamlessly with Hanami views, with features like automatic view rendering and support for a context object that gives views access to details like the current request. 7 | 8 | To learn more, see [Rendering from actions](/v2.1/views/rendering-from-actions/). 9 | -------------------------------------------------------------------------------- /content/v2.1/app/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: App 3 | order: 20 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/app/code-reloading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Code reloading 3 | order: 90 4 | aliases: 5 | - "/app/code-reloading" 6 | --- 7 | 8 | Hanami offers fast code reloading in development via the [hanami-reloader](https://github.com/hanami/reloader) gem. 9 | 10 | When you run `hanami server` in development, `guard` watches the file system for code edits and restarts the Hanami server when changes occur. 11 | 12 | Which directories are watched can be configured in the `Guardfile` of your project. 13 | 14 | ```ruby 15 | # Guardfile 16 | 17 | group :server do 18 | guard "puma", port: ENV["HANAMI_PORT"] || 2300 do 19 | watch(%r{config/*}) 20 | watch(%r{lib/*}) 21 | watch(%r{app/*}) 22 | watch(%r{slices/*}) 23 | end 24 | end 25 | ``` 26 | 27 | Hanami takes an "outside the framework" approach to code reloading. This has several advantages: 28 | 29 | - file system watching is delegated to `guard`. 30 | - Hanami internals are free from code reloading awareness. 31 | - if the hanami-reloader gem is not present (which is true in production), code reloading logic is eliminated. 32 | 33 | Thanks to [Zeitwerk](/v2.1/app/autoloading/) and [lazy loading](/v2.1/app/booting/), code reloading is also very fast. 34 | 35 | ### Reloading in the console 36 | 37 | If you have an existing console session and make a code change, you can use your updated code via the `reload` helper: 38 | 39 | ```ruby 40 | bundle exec hanami console 41 | 42 | bookshelf[development]> reload 43 | Reloading... 44 | ``` 45 | -------------------------------------------------------------------------------- /content/v2.1/assets/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assets 3 | order: 140 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/assets/customization.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Customization 3 | order: 30 4 | aliases: 5 | - "/assets/customization" 6 | --- 7 | 8 | To customize your assets compilation, update `config/assets.js` to match the following: 9 | 10 | ```js 11 | import * as assets from "hanami-assets"; 12 | 13 | await assets.run({ 14 | esbuildOptionsFn: (args, esbuildOptions) => { 15 | // Add to esbuildOptions here. Use `args.watch` as a condition for different options for 16 | // compile vs watch. 17 | 18 | return esbuildOptions; 19 | } 20 | }); 21 | ``` 22 | 23 | Inside `esbuildOptionsFn`, update `esbuildOptions` to set your own [esbuild options](https://esbuild.github.io/api/) for asset compilation. By the time this function runs, hanami-assets has set its own necessary options on `esbuildOptions`. 24 | 25 | If you want to apply different options when compiling assets (for production) versus watching assets (for development), use `args.watch` as a conditional. 26 | 27 | ```js 28 | await assets.run({ 29 | esbuildOptionsFn: (args, esbuildOptions) => { 30 | if (args.watch) { 31 | // watch mode (development) options here 32 | } else { 33 | // compile mode (production) options here 34 | } 35 | 36 | return esbuildOptions; 37 | } 38 | }); 39 | ``` 40 | 41 | ## Slice asset customization 42 | 43 | You can customise asset compilation for an individual slice by creating a `config/assets.js` within the slice directory. This will be used in preference to the config file at the top level. 44 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CLI commands 3 | order: 15 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/assets.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assets 3 | order: 100 4 | --- 5 | 6 | ## hanami assets compile 7 | 8 | Compiles the app's [assets](/v2.1/actions/overview) into bundles for use in production: 9 | 10 | ```shell 11 | $ bundle exec hanami assets compile 12 | [bookshelf] 13 | [bookshelf] public/assets/app-SQ36TYM4.js 53b 14 | [bookshelf] public/assets/app-KUHJPSX7.css 45b 15 | [bookshelf] public/assets/app-KUHJPSX7.css.map 93b 16 | [bookshelf] public/assets/app-SQ36TYM4.js.map 93b 17 | [bookshelf] 18 | [bookshelf] ⚡ Done in 3ms 19 | ``` 20 | 21 | ## hanami assets watch 22 | 23 | Watches for changes to your assets and compiles the relevant files immediately. This is a long-running command, and is run by [hanami dev](/v2.1/commands/dev) by default. 24 | 25 | ```shell 26 | $ bundle exec hanami assets watch 27 | [bookshelf] [watch] build finished, watching for changes... 28 | [bookshelf] [watch] build started (change: "app/assets/js/app.js") 29 | [bookshelf] [watch] build finished 30 | [bookshelf] [watch] build started (change: "app/assets/css/app.css") 31 | [bookshelf] [watch] build finished 32 | ``` 33 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Commands 3 | order: 10 4 | --- 5 | 6 | Hanami provides a command line interface with helpful commands for generating a new application, starting a console, starting a development server, displaying routes and more. 7 | 8 | ## Gem commands 9 | 10 | After an initial install via `gem install hanami`, hanami offers two commands: 11 | 12 | ```shell 13 | $ hanami --help 14 | 15 | Commands: 16 | hanami new APP # Generate a new Hanami app 17 | hanami version # Hanami version 18 | ``` 19 | 20 | ## App commands 21 | 22 | When executed from within a Hanami app, hanami offers a different set of commands. 23 | 24 | These commands can be listed using the `--help` flag. 25 | 26 | ```shell 27 | $ bundle exec hanami --help 28 | Commands: 29 | hanami assets [SUBCOMMAND] 30 | hanami console # Start app console (REPL) 31 | hanami dev # Start the application in development mode 32 | hanami generate [SUBCOMMAND] 33 | hanami install # Install Hanami third-party plugins 34 | hanami middleware # Print app Rack middleware stack 35 | hanami routes # Print app routes 36 | hanami server # Start Hanami app server 37 | hanami version # Print Hanami app version 38 | ``` 39 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/console.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Console 3 | order: 40 4 | --- 5 | 6 | ## hanami console 7 | 8 | Starts the Hanami console (REPL). 9 | 10 | ```shell 11 | $ bundle exec hanami console 12 | 13 | bookshelf[development]> 14 | ``` 15 | 16 | This command accepts an `engine` argument that can start the console using IRB or Pry. 17 | 18 | ```shell 19 | $ bundle exec hanami console --engine=irb # (the default) 20 | $ bundle exec hanami console --engine=pry 21 | ``` 22 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/dev.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dev 3 | order: 60 4 | --- 5 | 6 | ## hanami dev 7 | 8 | Starts Hanami application in development mode. 9 | 10 | ```shell 11 | $ bundle exec hanami dev 12 | ``` 13 | 14 | ### Procfile.dev 15 | 16 | Starting from Hanami 2.1, new apps have a `Procfile.dev`, where developers can manage the processes that should be managed by `hanami dev`. 17 | 18 | Those are the default contents: 19 | 20 | ```shell 21 | web: bundle exec hanami server 22 | assets: bundle exec hanami assets watch 23 | ``` 24 | 25 | ### bin/dev 26 | 27 | By default Hanami 2.1+, installs the `foreman` Ruby gem to run the `Procfile.dev`. 28 | 29 | In case you want use a different process manager, edit application's `bin/dev`. 30 | 31 | Example that uses [shoreman](https://github.com/chrismytton/shoreman), instead of `foreman`: 32 | 33 | ```shell 34 | #!/usr/bin/env sh 35 | shoreman Procfile.dev 36 | ``` 37 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/generate.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Generate 3 | order: 90 4 | --- 5 | 6 | ## hanami generate 7 | 8 | Hanami 2.1 provides a few generators: 9 | 10 | ```shell 11 | $ bundle exec hanami generate --help 12 | Commands: 13 | hanami generate action NAME 14 | hanami generate part NAME 15 | hanami generate slice NAME 16 | hanami generate view NAME 17 | ``` 18 | 19 | ### hanami generate action 20 | 21 | Generates an [action](/v2.1/actions/overview): 22 | 23 | ```shell 24 | $ bundle exec hanami generate action books.show 25 | ``` 26 | 27 | Use the `--help` option to access all accepted options: 28 | 29 | ```shell 30 | $ bundle exec hanami generate action --help 31 | ``` 32 | 33 | ### hanami generate part 34 | 35 | Generates a view [part](/v2.1/views/parts/): 36 | 37 | ```shell 38 | $ bundle exec hanami generate part book 39 | ``` 40 | 41 | Use the `--help` option to access all accepted options: 42 | 43 | ```shell 44 | $ bundle exec hanami generate part --help 45 | ``` 46 | 47 | ### hanami generate slice 48 | 49 | Generates a [slice](/v2.1/app/slices/): 50 | 51 | ```shell 52 | $ bundle exec hanami generate slice admin 53 | ``` 54 | 55 | Use the `--help` option to access all accepted options: 56 | 57 | ```shell 58 | $ bundle exec hanami generate slice --help 59 | ``` 60 | 61 | ### hanami generate view 62 | 63 | Generates a [view](/v2.1/views/overview/): 64 | 65 | ```shell 66 | $ bundle exec hanami generate view books.create 67 | ``` 68 | 69 | Use the `--help` option to access all accepted options: 70 | 71 | ```shell 72 | $ bundle exec hanami generate view --help 73 | ``` 74 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Install 3 | order: 30 4 | --- 5 | 6 | ## hanami install 7 | 8 | This command installs third-party dependencies (Ruby gems, NPM packages) and setups additional Hanami gems that provide code reloading, rspec, integrations. 9 | 10 |

11 | This command is executed automatically by hanami new. In case you'll run into third-party dependency problems, execute it. 12 |

13 | 14 | ```shell 15 | $ bundle exec hanami install 16 | ``` 17 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/middleware.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Middleware 3 | order: 80 4 | --- 5 | 6 | ## hanami middleware 7 | 8 | Displays the Rack middleware stack as currently configured. 9 | 10 | ```shell 11 | $ bundle exec hanami middleware 12 | 13 | / Dry::Monitor::Rack::Middleware (instance) 14 | / Rack::Session::Cookie 15 | / Hanami::Middleware::BodyParser 16 | ``` 17 | 18 | This command accepts a `--with-arguments` option that will include initialization arguments: 19 | 20 | ```shell 21 | $ bundle exec hanami middleware --with-arguments 22 | 23 | / Dry::Monitor::Rack::Middleware (instance) args: [] 24 | / Rack::Session::Cookie args: [{:key=>"my_app.session", :secret=>"secret", :expire_after=>31536000}] 25 | / Hanami::Middleware::BodyParser args: [:json] 26 | ``` 27 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/new.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: New 3 | order: 20 4 | --- 5 | 6 | ## hanami new 7 | 8 | Generates a Hanami application with the given APP name, in a new directory from the current location. 9 | 10 | ```shell 11 | $ hanami new bookshelf # generates a new Bookshelf application in ./bookshelf 12 | $ hanami new my_app # generates a new MyApp application in ./my_app 13 | ``` 14 | 15 | On the application generation, Hanami performs gem bundling, NPM bundling, and general application setup. 16 | 17 | ### Using Hanami HEAD 18 | 19 | In case you're interested to debug a Hanami issue, you can generate an application that uses the HEAD version of Hanami, directly from the `main` branches of the GitHub repositories. 20 | 21 | ```shell 22 | $ hanami new bookshelf --head 23 | ``` 24 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/routes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routes 3 | order: 70 4 | --- 5 | 6 | ## hanami routes 7 | 8 | Displays your application's routes. 9 | 10 | ```shell 11 | $ bundle exec hanami routes 12 | 13 | GET / home.index as :root 14 | GET /books books.index 15 | GET /books/:id books.show 16 | POST /books books.create 17 | ``` 18 | 19 | By default, routes are displayed in "human friendly" format. Routes can be inspected in csv format via the format option: 20 | 21 | ```shell 22 | $ bundle exec hanami routes --format=csv 23 | 24 | METHOD,PATH,TO,AS,CONSTRAINTS 25 | GET,/,home.index,:root,"" 26 | GET,/books,books.index,"","" 27 | GET,/books/:id,books.show,"","" 28 | POST,/books,books.create,"","" 29 | ``` 30 | -------------------------------------------------------------------------------- /content/v2.1/cli-commands/version.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Version 3 | order: 110 4 | --- 5 | 6 | ## hanami version 7 | 8 | Prints the version of the Hanami version used by the application: 9 | 10 | ```shell 11 | $ bundle exec hanami version 12 | v2.1.0 13 | ``` 14 | -------------------------------------------------------------------------------- /content/v2.1/helpers/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Helpers 3 | order: 130 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/helpers/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | --- 5 | 6 | Hanami provides a range of standard helpers for you to use in your views. 7 | 8 | You can read more about where helpers fit within your views in the [view helpers guide](/v2.1/views/helpers/). 9 | 10 | To learn more about Hanami's standard helpers, read the sections within this guide. 11 | -------------------------------------------------------------------------------- /content/v2.1/introduction/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | order: 10 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/introduction/hanami-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.1/introduction/hanami-welcome.png -------------------------------------------------------------------------------- /content/v2.1/logger/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Logger 3 | order: 80 4 | --- 5 | 6 | TBD 7 | -------------------------------------------------------------------------------- /content/v2.1/routing/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routing 3 | order: 40 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/upgrade-notes/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrade notes 3 | order: 170 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/views/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Views 3 | order: 75 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.1/views/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Configuration 3 | order: 100 4 | --- 5 | 6 | Forthcoming. 7 | -------------------------------------------------------------------------------- /content/v2.1/views/rendering-errors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rendering errors 3 | order: 90 4 | --- 5 | 6 | When running your app in production mode, error views will be rendered for any uncaught exceptions. This allows you to present a helpful error screen to your users while also hiding any technical details of the error. 7 | 8 | These error views are static HTML only. You can find them in your app's `public/` directory, at `404.html` and `500.html`. 9 | 10 | You can customize these views however you wish, though you should be mindful to keep their content static and self-contained to the HTML file as much as possible. 11 | 12 | ## Customizing error views 13 | 14 | You can enable or disable these error views using the `config.render_errors` app setting. This defaults to `true` when your app is in production mode, and `false` for all other modes. 15 | 16 | To configure which error views show for which exceptions, use the `config.render_error_responses` setting. This is a hash that maps string representations of Ruby exception classes to the symbolized form (downcased, underscored) of [Rack's list of HTTP error names](https://github.com/rack/rack/blob/f6c583adb0e863e524bacedaf594602964e01078/lib/rack/utils.rb#L469-L538). These names are then mapped to the equivalent status codes and used to locate the HTML files in `public/`. 17 | 18 | ```ruby 19 | # config/app.rb 20 | 21 | module Bookshelf 22 | class App < Hanami::App 23 | config.render_error_responses.merge!( 24 | "ROM::TupleCountMismatchError" => :not_found 25 | ) 26 | end 27 | end 28 | ``` 29 | -------------------------------------------------------------------------------- /content/v2.1/views/welcome-to-bookshelf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.1/views/welcome-to-bookshelf.png -------------------------------------------------------------------------------- /content/v2.1/views/working-with-dependencies.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Working with dependencies 3 | order: 10 4 | --- 5 | 6 | Hanami views are designed to work with dependencies from across your app. Using dependencies is how your view can retrieve the values it needs to include in its template. 7 | 8 | To include dependencies, use the Deps mixin: 9 | 10 | ```ruby 11 | # app/views/books/show.rb 12 | 13 | module Bookshelf 14 | module Views 15 | module Books 16 | class Show < Bookshelf::View 17 | include Deps["repositories.book_repo"] 18 | 19 | expose :book do |id:| 20 | book_repo.get!(id) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | ``` 27 | 28 | From here, you can use these dependencies within your [exposures](/v2.1/views/input-and-exposures/). 29 | -------------------------------------------------------------------------------- /content/v2.2/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | version: v2.2 3 | --- 4 | -------------------------------------------------------------------------------- /content/v2.2/actions/404-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.2/actions/404-response.png -------------------------------------------------------------------------------- /content/v2.2/actions/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Actions 3 | order: 50 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/actions/default-error-response.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.2/actions/default-error-response.png -------------------------------------------------------------------------------- /content/v2.2/actions/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | --- 5 | 6 | ## Actions 7 | 8 | In a Hanami application, actions are responsible for handling HTTP requests. Actions decide what HTTP response your application returns for a given request - its status, body, headers, whether to issue a redirect, and so on. 9 | 10 | Every action in your Hanami application is an individual class. Actions define a `#handle` method which takes two arguments: `request`, an object representing the incoming request, and `response`, an object representing the outgoing response. 11 | 12 | Modifying the response object allows you to control how your application responds to a request. 13 | 14 | ```ruby 15 | # app/actions/home/show.rb 16 | 17 | module Bookshelf 18 | module Actions 19 | module Home 20 | class Show < Bookshelf::Action 21 | def handle(request, response) 22 | name = request.params[:name] 23 | 24 | response.body = "Welcome to Bookshelf #{name}!" 25 | end 26 | end 27 | end 28 | end 29 | end 30 | ``` 31 | 32 | As the code above suggests, the `request` object provides access to the parameters associated with the incoming request through a `#params` method. 33 | 34 | Let's start by taking a look at action [parameters](/v2.2/actions/parameters/). 35 | -------------------------------------------------------------------------------- /content/v2.2/actions/rendering-views.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rendering views 3 | order: 35 4 | --- 5 | 6 | Hanami actions are designed to work seamlessly with Hanami views, with features like automatic view rendering and support for a context object that gives views access to details like the current request. 7 | 8 | To learn more, see [Rendering from actions](/v2.2/views/rendering-from-actions/). 9 | -------------------------------------------------------------------------------- /content/v2.2/app/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: App 3 | order: 20 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/app/code-reloading.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Code reloading 3 | order: 90 4 | --- 5 | 6 | Hanami offers fast code reloading in development via the [hanami-reloader](https://github.com/hanami/reloader) gem. 7 | 8 | When you run `hanami server` in development, `guard` watches the file system for code edits and restarts the Hanami server when changes occur. 9 | 10 | Which directories are watched can be configured in the `Guardfile` of your project. 11 | 12 | ```ruby 13 | # Guardfile 14 | 15 | group :server do 16 | guard "puma", port: ENV["HANAMI_PORT"] || 2300 do 17 | watch(%r{config/*}) 18 | watch(%r{lib/*}) 19 | watch(%r{app/*}) 20 | watch(%r{slices/*}) 21 | end 22 | end 23 | ``` 24 | 25 | Hanami takes an "outside the framework" approach to code reloading. This has several advantages: 26 | 27 | - file system watching is delegated to `guard`. 28 | - Hanami internals are free from code reloading awareness. 29 | - if the hanami-reloader gem is not present (which is true in production), code reloading logic is eliminated. 30 | 31 | Thanks to [Zeitwerk](/v2.2/app/autoloading/) and [lazy loading](/v2.2/app/booting/), code reloading is also very fast. 32 | 33 | ### Reloading in the console 34 | 35 | If you have an existing console session and make a code change, you can use your updated code via the `reload` helper: 36 | 37 | ```ruby 38 | bundle exec hanami console 39 | 40 | bookshelf[development]> reload 41 | Reloading... 42 | ``` 43 | -------------------------------------------------------------------------------- /content/v2.2/assets/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assets 3 | order: 140 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/assets/customization.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Customization 3 | order: 30 4 | --- 5 | 6 | To customize your assets compilation, update `config/assets.js` to match the following: 7 | 8 | ```js 9 | import * as assets from "hanami-assets"; 10 | 11 | await assets.run({ 12 | esbuildOptionsFn: (args, esbuildOptions) => { 13 | // Add to esbuildOptions here. Use `args.watch` as a condition for different options for 14 | // compile vs watch. 15 | 16 | return esbuildOptions; 17 | } 18 | }); 19 | ``` 20 | 21 | Inside `esbuildOptionsFn`, update `esbuildOptions` to set your own [esbuild options](https://esbuild.github.io/api/) for asset compilation. By the time this function runs, hanami-assets has set its own necessary options on `esbuildOptions`. 22 | 23 | If you want to apply different options when compiling assets (for production) versus watching assets (for development), use `args.watch` as a conditional. 24 | 25 | ```js 26 | await assets.run({ 27 | esbuildOptionsFn: (args, esbuildOptions) => { 28 | if (args.watch) { 29 | // watch mode (development) options here 30 | } else { 31 | // compile mode (production) options here 32 | } 33 | 34 | return esbuildOptions; 35 | } 36 | }); 37 | ``` 38 | 39 | ## Slice asset customization 40 | 41 | You can customise asset compilation for an individual slice by creating a `config/assets.js` within the slice directory. This will be used in preference to the config file at the top level. 42 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: CLI commands 3 | order: 15 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/assets.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Assets 3 | order: 110 4 | --- 5 | 6 | ## hanami assets compile 7 | 8 | Compiles the app's [assets](/v2.2/actions/overview) into bundles for use in production: 9 | 10 | ```shell 11 | $ bundle exec hanami assets compile 12 | [bookshelf] 13 | [bookshelf] public/assets/app-SQ36TYM4.js 53b 14 | [bookshelf] public/assets/app-KUHJPSX7.css 45b 15 | [bookshelf] public/assets/app-KUHJPSX7.css.map 93b 16 | [bookshelf] public/assets/app-SQ36TYM4.js.map 93b 17 | [bookshelf] 18 | [bookshelf] ⚡ Done in 3ms 19 | ``` 20 | 21 | ## hanami assets watch 22 | 23 | Watches for changes to your assets and compiles the relevant files immediately. This is a long-running command, and is run by [hanami dev](/v2.2/commands/dev) by default. 24 | 25 | ```shell 26 | $ bundle exec hanami assets watch 27 | [bookshelf] [watch] build finished, watching for changes... 28 | [bookshelf] [watch] build started (change: "app/assets/js/app.js") 29 | [bookshelf] [watch] build finished 30 | [bookshelf] [watch] build started (change: "app/assets/css/app.css") 31 | [bookshelf] [watch] build finished 32 | ``` 33 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/commands.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Commands 3 | order: 10 4 | --- 5 | 6 | Hanami provides a command line interface with helpful commands for generating a new application, starting a console, starting a development server, displaying routes and more. 7 | 8 | ## Gem commands 9 | 10 | After an initial install via `gem install hanami`, hanami offers two commands: 11 | 12 | ```shell 13 | $ hanami --help 14 | 15 | Commands: 16 | hanami new APP # Generate a new Hanami app 17 | hanami version # Hanami version 18 | ``` 19 | 20 | ## App commands 21 | 22 | When executed from within a Hanami app, hanami offers a different set of commands. 23 | 24 | These commands can be listed using the `--help` flag. 25 | 26 | ```shell 27 | $ bundle exec hanami --help 28 | Commands: 29 | hanami assets [SUBCOMMAND] 30 | hanami console # Start app console (REPL) 31 | hanami db [SUBCOMMAND] 32 | hanami dev # Start the application in development mode 33 | hanami generate [SUBCOMMAND] 34 | hanami install # Install Hanami third-party plugins 35 | hanami middleware # Print app Rack middleware stack 36 | hanami routes # Print app routes 37 | hanami server # Start Hanami app server 38 | hanami version # Print Hanami app version 39 | ``` 40 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/console.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Console 3 | order: 40 4 | --- 5 | 6 | ## hanami console 7 | 8 | Starts the Hanami console (REPL). 9 | 10 | ```shell 11 | $ bundle exec hanami console 12 | 13 | bookshelf[development]> 14 | ``` 15 | 16 | This command accepts an `engine` argument that can start the console using IRB or Pry. 17 | 18 | ```shell 19 | $ bundle exec hanami console --engine=irb # (the default) 20 | $ bundle exec hanami console --engine=pry 21 | ``` 22 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/dev.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Dev 3 | order: 60 4 | --- 5 | 6 | ## hanami dev 7 | 8 | Starts Hanami application in development mode. 9 | 10 | ```shell 11 | $ bundle exec hanami dev 12 | ``` 13 | 14 | ### Procfile.dev 15 | 16 | Starting from Hanami 2.1, new apps have a `Procfile.dev`, where developers can manage the processes that should be managed by `hanami dev`. 17 | 18 | Those are the default contents: 19 | 20 | ```shell 21 | web: bundle exec hanami server 22 | assets: bundle exec hanami assets watch 23 | ``` 24 | 25 | ### bin/dev 26 | 27 | By default Hanami 2.1+, installs the `foreman` Ruby gem to run the `Procfile.dev`. 28 | 29 | In case you want use a different process manager, edit application's `bin/dev`. 30 | 31 | Example that uses [shoreman](https://github.com/chrismytton/shoreman), instead of `foreman`: 32 | 33 | ```shell 34 | #!/usr/bin/env sh 35 | shoreman Procfile.dev 36 | ``` 37 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/install.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Install 3 | order: 30 4 | --- 5 | 6 | ## hanami install 7 | 8 | This command installs third-party dependencies (Ruby gems, NPM packages) and setups additional Hanami gems that provide code reloading, rspec, integrations. 9 | 10 |

11 | This command is executed automatically by hanami new. In case you'll run into third-party dependency problems, execute it. 12 |

13 | 14 | ```shell 15 | $ bundle exec hanami install 16 | ``` 17 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/middleware.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Middleware 3 | order: 100 4 | --- 5 | 6 | ## hanami middleware 7 | 8 | Displays the Rack middleware stack as currently configured. 9 | 10 | ```shell 11 | $ bundle exec hanami middleware 12 | 13 | / Dry::Monitor::Rack::Middleware (instance) 14 | / Rack::Session::Cookie 15 | / Hanami::Middleware::BodyParser 16 | ``` 17 | 18 | This command accepts a `--with-arguments` option that will include initialization arguments: 19 | 20 | ```shell 21 | $ bundle exec hanami middleware --with-arguments 22 | 23 | / Dry::Monitor::Rack::Middleware (instance) args: [] 24 | / Rack::Session::Cookie args: [{:key=>"my_app.session", :secret=>"secret", :expire_after=>31536000}] 25 | / Hanami::Middleware::BodyParser args: [:json] 26 | ``` 27 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/new.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: New 3 | order: 20 4 | --- 5 | 6 | ## hanami new 7 | 8 | Generates a Hanami application with the given APP name, in a new directory from the current location. 9 | 10 | ```shell 11 | $ hanami new bookshelf # generates a new Bookshelf application in ./bookshelf 12 | $ hanami new my_app # generates a new MyApp application in ./my_app 13 | ``` 14 | 15 | On the application generation, Hanami performs gem bundling, NPM bundling, and general application setup. 16 | 17 | ### Using Hanami HEAD 18 | 19 | In case you're interested to debug a Hanami issue, you can generate an application that uses the HEAD version of Hanami, directly from the `main` branches of the GitHub repositories. 20 | 21 | ```shell 22 | $ hanami new bookshelf --head 23 | ``` 24 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/routes.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routes 3 | order: 90 4 | --- 5 | 6 | ## hanami routes 7 | 8 | Displays your application's routes. 9 | 10 | ```shell 11 | $ bundle exec hanami routes 12 | 13 | GET / home.index as :root 14 | GET /books books.index 15 | GET /books/:id books.show 16 | POST /books books.create 17 | ``` 18 | 19 | By default, routes are displayed in "human friendly" format. Routes can be inspected in csv format via the format option: 20 | 21 | ```shell 22 | $ bundle exec hanami routes --format=csv 23 | 24 | METHOD,PATH,TO,AS,CONSTRAINTS 25 | GET,/,home.index,:root,"" 26 | GET,/books,books.index,"","" 27 | GET,/books/:id,books.show,"","" 28 | POST,/books,books.create,"","" 29 | ``` 30 | -------------------------------------------------------------------------------- /content/v2.2/cli-commands/version.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Version 3 | order: 120 4 | --- 5 | 6 | ## hanami version 7 | 8 | Prints the version of the Hanami version used by the application: 9 | 10 | ```shell 11 | $ bundle exec hanami version 12 | v2.2.0 13 | ``` 14 | -------------------------------------------------------------------------------- /content/v2.2/database/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Database 3 | order: 30 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/helpers/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Helpers 3 | order: 130 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/helpers/overview.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Overview 3 | order: 10 4 | --- 5 | 6 | Hanami provides a range of standard helpers for you to use in your views. 7 | 8 | You can read more about where helpers fit within your views in the [view helpers guide](/v2.2/views/helpers/). 9 | 10 | To learn more about Hanami's standard helpers, read the sections within this guide. 11 | -------------------------------------------------------------------------------- /content/v2.2/introduction/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Introduction 3 | order: 10 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/introduction/hanami-welcome.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.2/introduction/hanami-welcome.png -------------------------------------------------------------------------------- /content/v2.2/logger/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Logger 3 | order: 80 4 | --- 5 | 6 | TBD 7 | -------------------------------------------------------------------------------- /content/v2.2/operations/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Operations 3 | order: 70 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/routing/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Routing 3 | order: 40 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/upgrade-notes/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Upgrade notes 3 | order: 170 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/views/_index.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Views 3 | order: 75 4 | --- 5 | -------------------------------------------------------------------------------- /content/v2.2/views/configuration.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Configuration 3 | order: 100 4 | --- 5 | 6 | Forthcoming. 7 | -------------------------------------------------------------------------------- /content/v2.2/views/rendering-errors.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Rendering errors 3 | order: 90 4 | --- 5 | 6 | When running your app in production mode, error views will be rendered for any uncaught exceptions. This allows you to present a helpful error screen to your users while also hiding any technical details of the error. 7 | 8 | These error views are static HTML only. You can find them in your app's `public/` directory, at `404.html` and `500.html`. 9 | 10 | You can customize these views however you wish, though you should be mindful to keep their content static and self-contained to the HTML file as much as possible. 11 | 12 | ## Customizing error views 13 | 14 | You can enable or disable these error views using the `config.render_errors` app setting. This defaults to `true` when your app is in production mode, and `false` for all other modes. 15 | 16 | To configure which error views show for which exceptions, use the `config.render_error_responses` setting. This is a hash that maps string representations of Ruby exception classes to the symbolized form (downcased, underscored) of [Rack's list of HTTP error names](https://github.com/rack/rack/blob/f6c583adb0e863e524bacedaf594602964e01078/lib/rack/utils.rb#L469-L538). These names are then mapped to the equivalent status codes and used to locate the HTML files in `public/`. 17 | 18 | ```ruby 19 | # config/app.rb 20 | 21 | module Bookshelf 22 | class App < Hanami::App 23 | config.render_error_responses.merge!( 24 | "ROM::TupleCountMismatchError" => :not_found 25 | ) 26 | end 27 | end 28 | ``` 29 | -------------------------------------------------------------------------------- /content/v2.2/views/welcome-to-bookshelf.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/content/v2.2/views/welcome-to-bookshelf.png -------------------------------------------------------------------------------- /content/v2.2/views/working-with-dependencies.md: -------------------------------------------------------------------------------- 1 | --- 2 | title: Working with dependencies 3 | order: 10 4 | --- 5 | 6 | Hanami views are designed to work with dependencies from across your app. Using dependencies is how your view can retrieve the values it needs to include in its template. 7 | 8 | To include dependencies, use the Deps mixin: 9 | 10 | ```ruby 11 | # app/views/books/show.rb 12 | 13 | module Bookshelf 14 | module Views 15 | module Books 16 | class Show < Bookshelf::View 17 | include Deps["repos.book_repo"] 18 | 19 | expose :book do |id:| 20 | book_repo.get!(id) 21 | end 22 | end 23 | end 24 | end 25 | end 26 | ``` 27 | 28 | From here, you can use these dependencies within your [exposures](/v2.2/views/input-and-exposures/). 29 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build.environment] 2 | HUGO_VERSION = "v0.92.2" 3 | -------------------------------------------------------------------------------- /themes/hanami/LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2018 YOUR_NAME_HERE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /themes/hanami/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | +++ 3 | -------------------------------------------------------------------------------- /themes/hanami/layouts/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/layouts/404.html -------------------------------------------------------------------------------- /themes/hanami/layouts/_default/baseof.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | {{- partial "head.html" . -}} 4 | 5 | {{- partial "header.html" . -}} 6 |

7 | {{- block "main" . }}{{- end }} 8 |
9 | {{- partial "footer.html" . -}} 10 | 11 | 12 | -------------------------------------------------------------------------------- /themes/hanami/layouts/_default/list.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/layouts/_default/list.html -------------------------------------------------------------------------------- /themes/hanami/layouts/partials/head.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | -------------------------------------------------------------------------------- /themes/hanami/static/assets/img/brand/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/static/assets/img/brand/favicon.ico -------------------------------------------------------------------------------- /themes/hanami/static/assets/img/brand/hanami-guides-social.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/static/assets/img/brand/hanami-guides-social.png -------------------------------------------------------------------------------- /themes/hanami/static/assets/img/brand/purple.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/static/assets/img/brand/purple.png -------------------------------------------------------------------------------- /themes/hanami/static/assets/img/brand/white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/static/assets/img/brand/white.png -------------------------------------------------------------------------------- /themes/hanami/static/assets/img/theme/landing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/hanami/guides/3266c204d76adb5b112e43a789ec5b83bf3105c8/themes/hanami/static/assets/img/theme/landing.png -------------------------------------------------------------------------------- /themes/hanami/static/assets/js/theme.js: -------------------------------------------------------------------------------- 1 | (function($){ 2 | $(document).ready(function(){ 3 | // Navigation Documentation Version Select switch 4 | $('#navigation-version-switch').change(function (event) { 5 | var url = $(event.target).val() 6 | window.location.replace(url) 7 | }) 8 | 9 | // Search link 10 | $("#search-link").click(function(event) { 11 | event.preventDefault(); 12 | $("#search-form").fadeToggle(); 13 | }); 14 | 15 | // Alerts 16 | $("p.notice").prepend(''); 17 | $("p.convention").prepend(''); 18 | $("p.warning").prepend(''); 19 | 20 | // Sidebar menu 21 | var nonActiveMenuSections = $("ul.nav.ct-sidenav:not(:has(>.active))"); 22 | nonActiveMenuSections.hide() 23 | 24 | $("span.ct-toc-link").click(function(event){ 25 | event.preventDefault(); 26 | var element = $(this); 27 | var submenu = element.next("ul.nav.ct-sidenav"); 28 | 29 | nonActiveMenuSections.slideUp(); 30 | submenu.slideDown(); 31 | }); 32 | 33 | // Copy & Paste snippets 34 | $("div.highlight").before('
'); 35 | 36 | new ClipboardJS(".btn-clipboard", { 37 | text: function(button) { 38 | var btn = $(button); 39 | var code = btn.parent().next("div.highlight"); 40 | 41 | return code.text(); 42 | } 43 | }); 44 | }); 45 | })(jQuery); 46 | -------------------------------------------------------------------------------- /themes/hanami/static/assets/scss/bootstrap/_alert.scss: -------------------------------------------------------------------------------- 1 | // 2 | // Base styles 3 | // 4 | 5 | .alert { 6 | position: relative; 7 | padding: $alert-padding-y $alert-padding-x; 8 | margin-bottom: $alert-margin-bottom; 9 | border: $alert-border-width solid transparent; 10 | @include border-radius($alert-border-radius); 11 | } 12 | 13 | // Headings for larger alerts 14 | .alert-heading { 15 | // Specified to prevent conflicts of changing $headings-color 16 | color: inherit; 17 | } 18 | 19 | // Provide class for links that match alerts 20 | .alert-link { 21 | font-weight: $alert-link-font-weight; 22 | } 23 | 24 | 25 | // Dismissible alerts 26 | // 27 | // Expand the right padding and account for the close button's positioning. 28 | 29 | .alert-dismissible { 30 | padding-right: ($close-font-size + $alert-padding-x * 2); 31 | 32 | // Adjust close link position 33 | .close { 34 | position: absolute; 35 | top: 0; 36 | right: 0; 37 | padding: $alert-padding-y $alert-padding-x; 38 | color: inherit; 39 | } 40 | } 41 | 42 | 43 | // Alternate styles 44 | // 45 | // Generate contextual modifier classes for colorizing the alert. 46 | 47 | @each $color, $value in $theme-colors { 48 | .alert-#{$color} { 49 | @include alert-variant(theme-color-level($color, $alert-bg-level), theme-color-level($color, $alert-border-level), theme-color-level($color, $alert-color-level)); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /themes/hanami/static/assets/scss/bootstrap/_badge.scss: -------------------------------------------------------------------------------- 1 | // Base class 2 | // 3 | // Requires one of the contextual, color modifier classes for `color` and 4 | // `background-color`. 5 | 6 | .badge { 7 | display: inline-block; 8 | padding: $badge-padding-y $badge-padding-x; 9 | font-size: $badge-font-size; 10 | font-weight: $badge-font-weight; 11 | line-height: 1; 12 | text-align: center; 13 | white-space: nowrap; 14 | vertical-align: baseline; 15 | @include border-radius($badge-border-radius); 16 | 17 | // Empty badges collapse automatically 18 | &:empty { 19 | display: none; 20 | } 21 | } 22 | 23 | // Quick fix for badges in buttons 24 | .btn .badge { 25 | position: relative; 26 | top: -1px; 27 | } 28 | 29 | // Pill badges 30 | // 31 | // Make them extra rounded with a modifier to replace v3's badges. 32 | 33 | .badge-pill { 34 | padding-right: $badge-pill-padding-x; 35 | padding-left: $badge-pill-padding-x; 36 | @include border-radius($badge-pill-border-radius); 37 | } 38 | 39 | // Colors 40 | // 41 | // Contextual variations (linked badges get darker on :hover). 42 | 43 | @each $color, $value in $theme-colors { 44 | .badge-#{$color} { 45 | @include badge-variant($value); 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /themes/hanami/static/assets/scss/bootstrap/_breadcrumb.scss: -------------------------------------------------------------------------------- 1 | .breadcrumb { 2 | display: flex; 3 | flex-wrap: wrap; 4 | padding: $breadcrumb-padding-y $breadcrumb-padding-x; 5 | margin-bottom: $breadcrumb-margin-bottom; 6 | list-style: none; 7 | background-color: $breadcrumb-bg; 8 | @include border-radius($breadcrumb-border-radius); 9 | } 10 | 11 | .breadcrumb-item { 12 | // The separator between breadcrumbs (by default, a forward-slash: "/") 13 | + .breadcrumb-item { 14 | padding-left: $breadcrumb-item-padding; 15 | 16 | &::before { 17 | display: inline-block; // Suppress underlining of the separator in modern browsers 18 | padding-right: $breadcrumb-item-padding; 19 | color: $breadcrumb-divider-color; 20 | content: $breadcrumb-divider; 21 | } 22 | } 23 | 24 | // IE9-11 hack to properly handle hyperlink underlines for breadcrumbs built 25 | // without `