Hanami 3.0 released

hanami 3.0

Added

  • Integrate hanami-mailer gem when bundled. (@timriley in #1597, #1600, #1606, #1609)

    Load templates from templates/mailers/. Register a "mailers.delivery_method", which is either an SMTP mailer when SMTP_ADDRESS, SMTP_PORT, SMTP_USERNAME, SMTP_PASSWORD, SMTP_AUTHENTICATION env vars are present. These can also be prefixed with a slice name. Register a test delivery always in the test env, and also in other envs when the env vars are absent.

  • Integrate i18n gem when bundled. (@timriley in #1562, #1589, #1590, #1591, #1592, #1593)

    Register an "i18n" component in each slice, which may be configured via config.i18n or a dedicated :i18n provider. Load translations from config/i18n/ within each slice. Load shared translations from config/i18n/shared/ at the app-level only. Bundle default English translations for #localize. Make helpers available in views and actions, which also prefix relative keys (with a leading “.”) with their own dot-delimited template or action names.

  • Wrap the configured app logger with Hanami::UniversalLogger, to provide a consistent logging interface regardless of the underlying logger. The app can now be depended upon to support (1) structured logging via keyword args passed to log methods, and (2) tagged logging via #tagged. (@timriley in #1567, #1568, #1608)

  • Allow the built-in logger to be further configured in a config/providers/logger.rb provider file, useful for calling arbitrary methods on the logger, like adding backends. (@timriley in #1608)

    Hanami.app.configure_provider :logger do
      before :start do
        logger.add_backend(
          stream: Hanami.app.root.join("log", "payments.log"),
          log_if: -> entry { entry.tag?(:payments) }
        )
      end
    end
    
  • Support HANAMI_LOG_LEVEL env var to set the log level (e.g. HANAMI_LOG_LEVEL=warn bundle exec hanami server). Takes precedence over config.logger.level set in config/app.rb. (@cllns in #1580)

  • Add config.db.log_level setting, for changing the log level for SQL logs. (@katafrakt in #1587)

  • New setting :default_template_engine that sets which template engine should be used by default when doing hanami generate. (@katafrakt in #1564)

  • Add Hanami::Settings::CompositeStore, which can be used to chain setting lookups from multiple stores. (@aaronmallen in #1572)

  • Add Hanami::Slice.with_slices, returning the slice and all its nested slices. (@timriley in #1604)

Changed

  • Default to memoizing all components, except in test env. Opt out for some or all components via config.no_memoize. (@timriley in #1573, #1599)
  • Colorize logs by default in development env. (@timriley in #1566)
  • Emit structured log entries for SQL queries, formatted consistently with request logs. (@timriley in #1569)
  • Syntax highlight SQL in logs when the rouge gem is bundled. (@timriley in #1570, #1607)
  • Colorize web request logs. (@timriley in #1571)
  • Change default log level for SQL (and other database) statements from :info to :debug. (@katafrakt in #1595)
  • Raise a helpful error message when the Slice.call Rack entrypoint is called and no routes are available. (@sandbergja in #1586)
  • Apply extensions to hanami-action gem rather than hanami-controller (which is now retired). (@cllns in #1582)
  • Redesign the new app welcome screen to match our new Hanakai visuals. (@makenosound in #1598)
  • Require Ruby 3.3 or newer.

Removed

  • Remove default body parsing middleware. This functionality has moved into Hanami Action. (@timriley in #1575)

Compare v2.3.2 … v3.0.0


View release on GitHub

hanami-utils 3.0.0

Changed

  • Require Ruby 3.3 or newer.

Compare v2.3.0 … v3.0.0


View release on GitHub

hanami-router 3.0.0

Added

  • Add #permanent_redirect and #temporary_redirect helpers for 301 and 302 responses. (@cllns in #302)

Changed

  • BREAKING: #redirect now requires an explicit code: argument. Use #permanent_redirect or #temporary_redirect for the common cases, and pass code: to #redirect for less common codes (e.g. 303, 307, 308). (@cllns in #302)
  • Upgrade mustermann to 3.1 and remove mustermann-contrib dependency. (@rkh in #300)
  • Require Ruby 3.3 or newer.

Fixed

  • Only parse the request body into params when the content type is application/x-www-form-urlencoded. Previously, with no body parser middleware in use, posting a multipart upload (or other non-form body) could raise Rack::QueryParser::InvalidParameterError. (@cllns and @timriley in #305)
  • Allow URL generation (via #path) to work with array variables. (@inouire in #304)

Compare v2.3.1 … v3.0.0


View release on GitHub

hanami-view 3.0.0

Added

  • Track the currently-rendering template name. (@timriley in #277)

    Expose this as Hanami::View::Scope#_template_name (with template_name as a convenience alias) and Hanami::View::Context#current_template_name.

    The name is resolved path of the file actually being rendered, relative to its configured paths directory, with format/engine extensions stripped. For example, render("form") from inside posts/show.html.erb returns "posts/_form"; a layout at layouts/app.html.erb returns "layouts/app".

    The current template name can be used to enable such behaviors as lazy/relative key lookups for i18n view helpers.

Changed

  • BREAKING: Default to undecorated exposures. (@timriley in #274)

    Decorate your exposures with the new .decorate method, or the decorate: true option for .expose. Default back to decorated exposures via config.decorate_exposures = true.

  • Cache the view’s resolved configuration as a frozen Data snapshot (via dry-configurable’s #to_data) at initialization, avoiding repeated config lookups on the rendering hot path for improved memory usage and speed. (@cllns in #276)

  • Require Ruby 3.3 or newer.

Fixed

  • Allow the gem to be eager loaded by Zeitwerk when the optional haml and slim gems are not installed. (@timriley in #279)
  • Use our own Haml template engine even when the haml gem is required before hanami-view. (@timriley in #279)

Compare v2.3.1 … v3.0.0


View release on GitHub

hanami-action 3.0.0

Added

  • Parse request bodies based on formats config. (@timriley in #500, #503, #511, #519, @cllns in #508)

    Parsers for multipart form bodies and JSON are included by default. These require formats.accept :html and formats.accept :json respectively. When no formats are configured, multipart form bodies are parsed if found.

    Custom parsers may be registered via e.g. formats.register(:custom, "application/custom", parser: ->(body, env) { ... }) or directly via formats.body_parsers["application/custom"] = parser.

    Parsed body params are symbolized as part of becoming the Hanami::Action::Params instance. Non-hash bodies are wrapped in {"_" => parsed_body}.

  • Support additional Cache-Control directives in response.cache_control: :immutable, :must_understand, stale_while_revalidate: and stale_if_error:. (@timriley in #522)

  • Full JRuby support. (@katafrakt in #498)

Changed

  • Renamed gem from hanami-controller to hanami-action. You should now require "hanami-action" or require "hanami/action". (@timriley in #507, @cllns in df365b5)

  • Check for the dry-validation gem (instead of hanami-validations, which is now retired) before loading Action.params and Action.contract support. (@timriley in #505)

  • Raise ArgumentError from response.cache_control for unknown directives, instead of silently dropping them. (@timriley in #522)

  • Cache the action’s resolved configuration as a frozen Data snapshot (via dry-configurable’s #to_data) at initialization, avoiding repeated config lookups on the request hot path for improved memory usage and speed. Required bumping dry-configurable to ~> 1.4. (@cllns in #512)

    Possibly breaking: the action’s config is now finalized (frozen) when the action is initialized, so mutating it from instance code is no longer possible. This was only ever an undocumented side-effect of implementation, not a supported pattern.

  • Cut per-request allocations on the Hanami::Action#call hot path, roughly halving allocations and increasing throughput ~1.5–2.5x per action invocation. A minimal action drops from 51 to 16 allocations (69% fewer, 2.45x faster); an action with formats negotiating an Accept header drops from 95 to 61 allocations (36% fewer, 1.55x faster). (@cllns in #514)

  • Require Ruby 3.3 or newer.

Removed

  • Removed deprecated format config methods: Action.format, config.format, config.formats.add, config.formats.values. (@timriley in #504)

  • Removed Hanami::Action::Params.params and support for defining a contract by subclassing Hanami::Action::Params. If you are subclassing Hanami::Action::Params, take your params block and move it into a Dry::Validation::Contract subclass. Then pass this contract class to Hanami::Action.params or Hanami::Action.contract. (@timriley in #513)

    # Before
    # class SignupParams < Hanami::Action::Params
    #   params do
    #     required(:email).filled(:str?)
    #   end
    # end
    
    # After
    class SignupContract < Dry::Validation::Contract
      params do
        required(:email).filled(:str?)
      end
    end
    
    class Signup < Hanami::Action
      params SignupParams
    end
    

Compare v2.3.2 … v3.0.0


View release on GitHub

hanami-mailer 3.0.0

Changed

  • Rewrite the gem. (@timriley)
  • Require Ruby 3.3 or newer.

Compare v1.3.3 … v3.0.0


View release on GitHub

hanami-assets 3.0.0

Added

Changed

  • Require Ruby 3.3 or newer.

Compare v2.3.0 … v3.0.0


View release on GitHub

hanami-assets 3.0.0 (npm)

Added

  • Detect newly added entry points while in watch mode. (@timriley in #48)
  • Detect changes to static files while in watch mode. (@timriley in #46)

Changed

  • Skip .DS_Store files during build and watch. (@kyleplump in #37)

  • Breaking: Make esbuild a peer dependency. (@timriley in #51)

    Your app must now depend on esbuild directly. This allows you to update esbuild on your own schedule without waiting for a new hanami-assets release.

  • Bump minimum supported esbuild to 0.28.1. (@timriley in #51)

  • Require Node.js v22 or newer. (@timriley in #47)

Compare v2.3.3 … v3.0.0


View release on GitHub

hanami-cli 3.0.0

Added

  • Include hanami-mailer in the default Gemfile, include sample mailer env vars in .env, and generate a base Mailer class for the app and each slice (app/mailer.rb and mailer.rb in slices). Use hanami new --skip-mailer to opt out. (@timriley in #420, #425)
  • Add generate mailer command. (@timriley in #426)
  • Add i18n gem to the default Gemfile, and generate a placeholder config/i18n/en.yml for the app and each generated slice. (@timriley in #409)
  • Add --name option to hanami new, to specify a custom module namespace while using the positional argument as the directory path. For example, hanami new my_bookshelf --name=bookshelf creates the app in my_bookshelf/ with Bookshelf as the module name. (@aaronmallen in #387)
  • Add --test option to hanami new to specify which test framework to use. Supports rspec (default) and minitest. (@timriley in #399)
  • Add generate provider command. (@timriley in #419)
  • Add --template-engine option to hanami generate and hanami new to specify which template engine should be used for generated template files. Supports erb, haml and slim. (@katafrakt in #280, #389, #390)
  • Add --force option to all generators (except migration), which will override existing files instead of exiting early (@katafrakt in #397)
  • Add a --skip-test-db flag to hanami db commands. By default, running a db command in development also re-runs against the test database to keep the two in sync; passing --skip-test-db operates on the development database only. (@adamlassek in #430)

Changed

  • In generated Gemfile, depend on dry-validation rather than hanami-validations. Hanami Validations will no longer be used; Hanami Action now checks for Dry Validation directly. (@timriley in #401)
  • In generated package.json, include esbuild as a direct dependency. esbuild is now a peer dependency of hanami-assets, which requires the app to depend on it directly. (@timriley in #428)
  • Check for the hanami-action gem rather than hanami-controller (now retired) across various commands. (@cllns in #402)
  • Include rouge gem in generated Gemfile to enable SQL syntax highlighting in logs. (@kyleplump in #405)
  • When --gem-source=gem.coop is used, Hanami and Dry gems are installed from their respective namespaces on gem.coop (@katafrakt in #424)
  • Require Puma 7.1 or later, and remove unneeded preload_app! in generated config/puma.rb. Preloading is now enabled by default in Puma’s cluster mode. (@joshuay03 in #372)
  • In generated .env, include a link the guide explaining how these files are loaded. (@timriley in #425)
  • In generated files, update all guides.hanamirb.org links to hanakai.org. (@yosangwon in #407)
  • Require dry-cli 1.4 or later, allowing for simplified argument handling in hanami-rspec callback methods. (@timriley in #408)
  • Link to new hanakai.org site in generated README.md. (@katafrakt in #423)
  • Require Ruby 3.3 or newer.

Fixed

  • Skip generating duplicate routes when running generate action. (@sandbergja in #417)
  • Don’t overwrite libpq ENV vars with empty strings derived from certain DATABASE_URLs. (@StantonMatt in #414)
  • Remove duplicate text in middleware and routes command usage output. (@katafrakt in #406)

Compare v2.3.5 … v3.0.0


View release on GitHub

hanami-db 3.0.0

Changed

  • Require Ruby 3.3 or newer.

Compare v2.3.0 … v3.0.0


View release on GitHub

hanami-rspec 3.0.0

View release on GitHub

hanami-minitest 3.0.0

Added


View release on GitHub

hanami-webconsole 3.0.0

Changed

  • Update to binding_of_caller 2.0, which formally supports Ruby 4.0. Remove our internal workarounds for this. (@rvmtz in #14)
  • Require Ruby 3.3 or newer.

Compare v2.3.3 … v3.0.0


View release on GitHub

hanami-reloader 3.0.0

Changed

  • Require Ruby 3.3 or newer.

Compare v2.3.0 … v3.0.0


View release on GitHub

hanami-utils 3.0.1

Changed

Compare v3.0.0 … v3.0.1


View release on GitHub

hanami-action 3.0.1

Adding an improvement that was originally intended for 3.0.0.

Added

  • Support additional Cache-Control directives in response.cache_control: :immutable, :must_understand, stale_while_revalidate: (requires a duration) and stale_if_error: (requires a duration). (@timriley in #522)

Changed

  • response.cache_control raises ArgumentError for unknown directives instead of silently dropping them. (@timriley in #522)

Compare v3.0.0 … v3.0.1


View release on GitHub

hanami 3.0.1

Fixed

  • Only configure template for mailer classes if hanami-view is bundled. (@katafrakt in #1611)

Compare v3.0.0 … v3.0.1


View release on GitHub