diff --git a/README.md b/README.md index 31c1223..156655c 100644 --- a/README.md +++ b/README.md @@ -10,7 +10,7 @@ pairing with smart people at Hashrocket. For a steady stream of TILs, [sign up for my newsletter](https://crafty-builder-6996.ck.page/e169c61186). -_1680 TILs and counting..._ +_1681 TILs and counting..._ See some of the other learning resources I work on: @@ -1051,6 +1051,7 @@ If you've learned something here, support my efforts writing daily TILs by - [Comparing DateTimes Down To Second Precision](rails/comparing-datetimes-down-to-second-precision.md) - [Conditional Class Selectors in Haml](rails/conditional-class-selectors-in-haml.md) - [Convert A Symbol To A Constant](rails/convert-a-symbol-to-a-constant.md) +- [Convert JSON Field To Hash With Indifferent Access](rails/convert-json-field-to-hash-with-indifferent-access.md) - [Count The Number Of Records By Attribute](rails/count-the-number-of-records-by-attribute.md) - [Create A Custom Named References Column](rails/create-a-custom-named-references-column.md) - [Create A Join Table With The Migration DSL](rails/create-a-join-table-with-the-migration-dsl.md) diff --git a/rails/convert-json-field-to-hash-with-indifferent-access.md b/rails/convert-json-field-to-hash-with-indifferent-access.md new file mode 100644 index 0000000..9f5974b --- /dev/null +++ b/rails/convert-json-field-to-hash-with-indifferent-access.md @@ -0,0 +1,36 @@ +# Convert JSON Field To Hash With Indifferent Access + +Let's say we have an `Event` model whose backing table includes a `JSONB` (or +`JSON`) field called `details`. + +When we access `details` in a Rails context, digging into that nested data we +have to use string keys throughout. However, we may have existing related code +that is dealing with this shape of data using symbol keys. This might put us in +a position where we have to rework a bunch of existing code or do defensive +coding like `details[:user] || details["user"]`. + +To avoid that, we can instead have the `Event` model override `details` +converting that underlying data to `HashWithIndifferentAccess` before returning +it. + +```ruby +class Event < ApplicationRecord + def details + data = super + return data if data.nil? + + case data + when Array + data.map { |item| item.is_a?(Hash) ? item.with_indifferent_access : item } + when Hash + data.with_indifferent_access + else + data + end + end +end +``` + +With this in place, anywhere in the codebase where we access `details` on an +instance of `Event` we will be able to use string or symbol keys +interchangeably.