# Hanami 1.3 -\> Hanami 2.0

**URL:** <https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702>\
**Category:** questions\
**Created:** [August 5, 2022, 11:21pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702 "2022-08-05T23:21:25Z")\
**Posts on this page:** 20\
**Page:** 1

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [August 5, 2022, 11:21pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/1 "2022-08-05T23:21:25Z")

</div>

I’ve started working on upgrading our projects from Hanami 1.3 → 2.0 and I’ll document my journey as I progress.

1. This post will be updated as the time goes
2. When (Not _IF_ 😅 ) I’ll encounter some blockers, I’ll ask here for help in this thread.
3. At the end I’ll compose a blog post (and guides chapter?) out of our findings here.

**Any contribution to discussions appreciated** 🙂

### Upgrade Steps

1. Get Rid of Hanami Model → Switch to ROM 5.0
2. Upgrade Ruby 2.7 → 3.1
3. Upgrade all DRY Libraries
4. Update Hanami → Hanami 2

Please let me know if you have more ideas, or need further help!

### Resources

- [Video Briefing through Hanami Model → Switch to ROM 5](https://www.youtube.com/watch?v=JWLVWavA3GE&feature=youtu.be)

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [August 5, 2022, 11:28pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/2 "2022-08-05T23:28:52Z")

</div>

**My first trouble:**

I have JSONB columns in my entities. Before, reading them by Hanami::Model, resulted in a hash. After switching to ROM, the column read from DB returns JSON.

```ruby
# Before (Hanami::Model)
message.payload
# => { author: "Jsmith", content: "My message" }

# After (ROM 5.0)

# frozen_string_literal: true

module Entities
  class Message < ROM::Struct
  end
end

# frozen_string_literal: true

module Persistence
  module Relations
    class Messages < ROM::Relation[:sql]
      schema(:messages, infer: true)

      auto_struct true
    end
  end
end

class MessageRepository < Rom::Repository[:messages]
end

MessageRepository.new.messages.first.payload
# => "{\"author\":\"Jsmith\",\"content\":\"My message\"}"

```

Question: How I should configure a Mapper for all JSONB columns in my system at once?

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/alassek/32/532_2.png) [@alassek](https://discourse.hanakai.org/u/alassek)\
**Post date:** [August 10, 2022, 1:58am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/3 "2022-08-10T01:58:16Z")

</div>

Enable the [`pg_json` extension](https://sequel.jeremyevans.net/rdoc-plugins/files/lib/sequel/extensions/pg_json_rb.html) from Sequel.

I’m not using Hanami yet but my dry-system app has this:

```ruby
rom_config = ROM::Configuration.new(
  :sql,
  target[:settings].database_url,
  extensions: %i[pg_array pg_json]
)

```

Nothing specific needs to be done within ROM itself, in my experience.

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [August 10, 2022, 6:28am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/4 "2022-08-10T06:28:30Z")

</div>

Thanks! Unfortunately did not work :(. Still when I read the `payload`, I get JSON` instead Hash`

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/alassek/32/532_2.png) [@alassek](https://discourse.hanakai.org/u/alassek)\
**Post date:** [August 10, 2022, 10:02pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/5 "2022-08-10T22:02:30Z")

</div>

Here’s an example script that works for me

```ruby
#!/usr/bin/env ruby

require 'bundler/inline'

gemfile(true) do
  source 'https://rubygems.org'

  gem 'pg'
  gem 'sequel_pg', require: 'sequel'
  gem 'rom', '~> 5'
  gem 'rom-sql'
end

require 'open3'

o, e, s = Open3.capture3("psql -c 'CREATE DATABASE rom_example'")
s.success? ? puts(o) : abort(e)

o, e, s = Open3.capture3('psql rom_example', stdin_data: <<~SQL)
  CREATE schema public;

  CREATE TABLE public.messages (
    id bigint NOT NULL,
    payload jsonb NOT NULL default '{}'
  );
SQL

s.success? ? puts(o) : abort(e)

require 'sequel'
require 'rom'
require 'rom/sql'

ROM::SQL.load_extensions :postgres

config = ROM::Configuration.new(:sql, "postgres://localhost:5432/rom_example", extensions: %i[pg_json])

config.relation(:messages) do
  schema(infer: true)
  auto_struct true
end

rom = ROM.container(config)
relation = rom.relations[:messages]

attrs = { id: 1, payload: { author: "John Smith", content: "My message" } }
relation.changeset(:create, attrs).commit

message = relation.where(id: 1).one
puts "MESSAGE PAYLOAD: #{message.payload.inspect}"

rom.gateways[:default].disconnect
system "psql -c 'drop database rom_example'"

```

```auto
$ ./example.rb
Fetching gem metadata from https://rubygems.org/.......
Resolving dependencies...
Using bundler 2.3.3
Using dry-initializer 3.1.1
Using method_source 1.0.0
Using pg 1.4.3
Using transproc 1.1.1
Using sequel 5.59.0
Using coderay 1.1.3
Using dry-inflector 0.3.0
Using ice_nine 0.11.2
Using concurrent-ruby 1.1.10
Using dry-equalizer 0.3.0
Using pry 0.14.1
Using sequel_pg 1.15.0
Using dry-core 0.8.1
Using dry-container 0.10.1
Using dry-logic 1.2.0
Using dry-types 1.5.1
Using dry-struct 1.4.0
Using rom-core 5.2.6
Using rom-changeset 5.2.3
Using rom-repository 5.2.2
Using rom 5.2.6
Using rom-sql 3.5.0
Expanded display is used automatically.
Null display is "¤".
CREATE DATABASE
Expanded display is used automatically.
Null display is "¤".
CREATE TABLE
MESSAGE PAYLOAD: {"author"=>"John Smith", "content"=>"My message"}
Expanded display is used automatically.
Null display is "¤".
DROP DATABASE

```

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [August 11, 2022, 10:14pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/6 "2022-08-11T22:14:47Z")

</div>

@alassek Thank you! It actually worked! It appears, I loaded extensions and plugins wrongly.

I experienced more problems, as the `Sequel::Postgres::JSONHash` returns stringified keys, while the rest of attributes symbolized and it can’t be stringified via: `Hanami::Utils::Hash.deep_stymbolize(attrs)`

I’ve handled that. However, I got stucked with other advanced query magic with Sequel and ROM mix :(.

### OLD Code from Hanami 1 (ROM 3.X)

```ruby
# foos_by_users
before = Date.today.to_time.strftime('%Y-%m-%dT%H:%M:%S.%LZ')

foos
  .select { `data->>'user_id'`.as(:user_id) }
  .select_append { `MAX(data->>'featured_at')`.as(:featured_at) }
  .where(Sequel.lit("data->>'featured_at' <= ?", before))
  .group(:user_id)
  .order(nil)
  .pluck(%i(user_id featured_at))
  .to_h

```

### Question: How to translate this to ROM 5?

Running above returns the error:

```shell
KeyError:
 :user_id attribute doesn't exist in foos schema

```

In new ROM syntax, select blocks should contain array instead of single objects.

```ruby
foos
  .select do
    [
      `data->>'user_id'`.as(:user_id)
      `MAX(data->>'featured_at')`.as(:featured_at)
    ]
  end
   # ...

```

But still, .`group(:user_id)` does not see the attribute.

I’ve tried also:

```ruby
.group(`data->>'user_id'`)

```

but this returns the undefined method error

```shell
     NoMethodError:
       undefined method `qualified_projection' for [:user_id, :featured_at]:Array

```

This looks like the `pluck` happens before grouping, or whatever.

cc: @solnic

---

<div class="post-metadata">

**Author:** ![alassek](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/alassek/32/532_2.png) [@alassek](https://discourse.hanakai.org/u/alassek)\
**Post date:** [August 12, 2022, 6:58am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/7 "2022-08-12T06:58:06Z")

</div>

I have a particular interest in SQL ASTs so this was an amusing diversion, although the software engineer in me wonders if this might be simpler to just implement as a database view.

This is complex so I’m going to take this a piece at a time.

### SQL literals

There’s nothing _wrong_ with using literals this way but there are Ruby interfaces for what you’re doing.

```ruby
.select { data.pg_jsonb.get_text('user_id').as(:user_id) }
.select_append { function(:MAX, data.pg_jsonb.get_text('featured_at')).as(:featured_at) }
.where { data.pg_jsonb.get_text('featured_at') <= Date.today.to_time }

```

The [`pg_jsonb` interface](https://github.com/jeremyevans/sequel/blob/master/lib/sequel/extensions/pg_json_ops.rb) is less than ideal but it gets the job done.

### GROUP BY

Method parameters are schema attributes, [blocks are schema attributes _and_ virtual columns](https://github.com/rom-rb/rom-sql/blob/cebc4fcbc8b4d320867fdf2db9226090e848199c/lib/rom/sql/group_dsl.rb#L12-L18)

```ruby
.group { user_id }

```

### Pluck

Pluck is [implemented as `select` + `map`](https://github.com/rom-rb/rom-sql/blob/cebc4fcbc8b4d320867fdf2db9226090e848199c/lib/rom/sql/relation/reading.rb#L165). You’re already selecting so just try map here

```ruby
.map(%i[user_id featured_at])

```

> <https://gist.github.com/alassek/c6408227d6ed501740bc70d594e81490>

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/solnic/32/757_2.png) [@solnic](https://discourse.hanakai.org/u/solnic)\
**Post date:** [August 12, 2022, 8:02am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/8 "2022-08-12T08:02:47Z")

</div>

@swilgosz `Relation#pluck` is supposed to be used to return values from specific columns, it doesn’t support projected columns. You can probably skip `pluck` and just do `.to_hash(:user_id, :featured_at)`.

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [August 16, 2022, 8:37am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/9 "2022-08-16T08:37:32Z")

</div>

Thank you!

I needed to add set Sequel.lit for grouping:

```ruby
.groupSequel.lit(`data->>'user_id'`)

```

But the `pluck` accepting list of symbols instead of array was another issue. Thanks for the quick reply!

---

<div class="post-metadata">

**Author:** ![solnic](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/solnic/32/757_2.png) [@solnic](https://discourse.hanakai.org/u/solnic)\
**Post date:** [August 16, 2022, 10:06am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/10 "2022-08-16T10:06:59Z")

</div>

> [@swilgosz](#):
>
> I needed to add set Sequel.lit

There shouldn’t be any need for using this. There are PG JSONB helpers that you can use in blocks like showed above.

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [August 16, 2022, 10:54am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/11 "2022-08-16T10:54:27Z")

</div>

Thanks, will play with it more.

BTW: I found that PG:: JSON returns stringified hash while the rest of Entities is accessible via symbolized hash. What would be the best way ro unify this?

I have written the custom type on top of PG::JSONB, but it requires me to define all JSONB columns in relations manually.

Wondering if there is better approach

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [September 13, 2022, 8:47am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/12 "2022-09-13T08:47:16Z")

</div>

It seems I cannot edit the Main post in the thread anymore (probably too old), so I’ll add the resources in the comments.

- [Article: Part 1 - Migrations upgrade](https://loyalty.dev/posts/upgrading-hanami-part-one)

---

<div class="post-metadata">

**Author:** ![cc-kawakami](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/cc-kawakami/32/610_2.png) [@cc-kawakami](https://discourse.hanakai.org/u/cc-kawakami)\
**Post date:** [February 10, 2023, 8:05am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/13 "2023-02-10T08:05:11Z")

</div>

How do you think about migration of views and templates ?

> **[V2.0: Planned for 2.1 | Hanami Guides](https://guides.hanamirb.org/v2.0/views/planned_for_2_1/)**
>
> V2.0: Planned for 2.1 | Hanami Guides

---

<div class="post-metadata">

**Author:** ![radanskoric](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/radanskoric/32/272_2.png) [@radanskoric](https://discourse.hanakai.org/u/radanskoric)\
**Post date:** [March 17, 2023, 11:35am UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/14 "2023-03-17T11:35:11Z")

</div>

Hi, this thread is the closest thing I found to a guide for upgrading from Hanami 1.3.5 to 2.

The link on the official guides page ([https://guides.hanamirb.org/](https://guides.hanamirb.org/)) is broken. It points to: [https://guides.hanamirb.org/upgrade-notes/v200](https://guides.hanamirb.org/upgrade-notes/v200) which doesn’t exist: [guides/content/v1.3/upgrade-notes at main · hanami/guides · GitHub](https://github.com/hanami/guides/tree/main/content/v1.3/upgrade-notes).

I’ve got a pet project I’m working on in my spare time that’s on Hanami 1.3.5. I’d be grateful if someone could point me to where I should start to upgrade it to 2.0? Is there any blog post or documentation?

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [March 17, 2023, 12:35pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/15 "2023-03-17T12:35:22Z")

</div>

As far as I know, I am the only person that spends effort on figuring things out on big projects at the moment.

Top level path for you to follow:

1. Upgrade ruby to 2.7.7
2. Lock hanami at 1.3.4 (1.3.5 does not introduce any new features but prevents installing ruby 3)
3. Replace Hanami-Model with ROM 3 (or ROM 5 directly if project is small)
4. Update all dry gems
5. Install hanami overrides for [ruby 3 support, version 0.0.3](https://github.com/Kaligo/hanami-ruby3) and [Hanami-Utils overrides](https://github.com/swilgosz/hanami-utils/tree/1.3.x-support-ruby-3.0)
6. Remove all ruby 3 deprecation warnings.
7. Update Ruby to 3.0
8. Then switch to Hanami 2 (this is yet by me to figure out, I’m currently on point 5 in our applications in Ascenda.)

More detailed guides will be released as soon as I’ll finish the complete first upgrade in Ascenda.

---

<div class="post-metadata">

**Author:** ![radanskoric](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/radanskoric/32/272_2.png) [@radanskoric](https://discourse.hanakai.org/u/radanskoric)\
**Post date:** [March 17, 2023, 12:54pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/16 "2023-03-17T12:54:08Z")

</div>

Thank you for this, I’ll try following that.

Do you maybe have a WIP upgrade guide somewhere? I’d be interested in contributing to it as I’m trying to upgrade.

It currently doesn’t look good for Hanami to not have a an upgrade guide almost 4 months after the release. Especially with the link on the official guides page broken. 🙂

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [March 17, 2023, 12:59pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/17 "2023-03-17T12:59:27Z")

</div>

Let me fix this link first. I will post our team notes as a document you can contribute to after the weekend

---

<div class="post-metadata">

**Author:** ![swilgosz](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/swilgosz/32/484_2.png) [@swilgosz](https://discourse.hanakai.org/u/swilgosz)\
**Post date:** [March 17, 2023, 1:10pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/18 "2023-03-17T13:10:07Z")

</div>

> [@radanskoric](#):
>
> It currently doesn’t look good for Hanami to not have a an upgrade guide almost 4 months after the release.

I agree, let’s join efforts to speed it up:). I have not yet freed up a dedicated day for OSS/content creation, still on my way to do so but things are progressing in the right direction:)

---

<div class="post-metadata">

**Author:** ![radanskoric](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/radanskoric/32/272_2.png) [@radanskoric](https://discourse.hanakai.org/u/radanskoric)\
**Post date:** [March 17, 2023, 1:17pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/19 "2023-03-17T13:17:48Z")

</div>

I’d be very happy to help! The project is a pet project so I work on it when I have time which is not often but I am hoping to update it to 2.0 over the next 2 months and I’ll be very happy to amend and extend a guide.

I can also start it from scratch but if there is anything already written it’s going to go much faster if I contribute to that. 🙂

---

<div class="post-metadata">

**Author:** ![radanskoric](https://yyz2.discourse-cdn.com/flex030/user_avatar/discourse.hanakai.org/radanskoric/32/272_2.png) [@radanskoric](https://discourse.hanakai.org/u/radanskoric)\
**Post date:** [March 29, 2023, 4:12pm UTC](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702/20 "2023-03-29T16:12:16Z")

</div>

@swilgosz you mentioned some notes you might share and that you already upgraded your models to ROM? Would it be possible to see the notes? I’ve picked up the upgrade of my (small) side project and I’m struggling a bit to switch from Hanami models to ROM since I haven’t used ROM on its own before.

[Next page](https://discourse.hanakai.org/t/hanami-1-3-hanami-2-0/702.md?page=2)
