{"id":13879757,"url":"https://github.com/madeintandem/jsonb_accessor","last_synced_at":"2026-10-19T16:40:58.959Z","repository":{"id":29738516,"uuid":"33281933","full_name":"madeintandem/jsonb_accessor","owner":"madeintandem","description":"Adds typed jsonb backed fields to your ActiveRecord models.","archived":false,"fork":false,"pushed_at":"2026-06-22T10:05:06.000Z","size":583,"stargazers_count":1127,"open_issues_count":12,"forks_count":99,"subscribers_count":28,"default_branch":"master","last_synced_at":"2026-10-14T16:27:18.080Z","etag":null,"topics":["activerecord","jsonb","jsonb-accessor","postgres","query","ruby"],"latest_commit_sha":null,"homepage":"","language":"Ruby","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/madeintandem.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"accessibility":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"claude":null,"gemini":null,"cursor":null,"copilot":null,"dco":null,"cla":null,"disclosure":null}},"created_at":"2015-04-02T01:14:40.000Z","updated_at":"2026-09-25T11:22:15.000Z","dependencies_parsed_at":"2026-10-13T05:36:47.607Z","dependency_job_id":null,"html_url":"https://github.com/madeintandem/jsonb_accessor","commit_stats":null,"previous_names":["devmynd/jsonb_accessor"],"tags_count":31,"template":false,"template_full_name":null,"purl":"pkg:github/madeintandem/jsonb_accessor","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madeintandem%2Fjsonb_accessor","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madeintandem%2Fjsonb_accessor/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madeintandem%2Fjsonb_accessor/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madeintandem%2Fjsonb_accessor/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/madeintandem","download_url":"https://codeload.github.com/madeintandem/jsonb_accessor/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/madeintandem%2Fjsonb_accessor/sbom","scorecard":{"id":610203,"data":{"date":"2025-08-11","repo":{"name":"github.com/madeintandem/jsonb_accessor","commit":"509bca99bc25a203156dcf725984a1269dd127d1"},"scorecard":{"version":"v5.2.1-40-gf6ed084d","commit":"f6ed084d17c9236477efd66e5b258b9d4cc7b389"},"score":4.6,"checks":[{"name":"Packaging","score":-1,"reason":"packaging workflow not detected","details":["Warn: no GitHub/GitLab publishing workflow detected."],"documentation":{"short":"Determines if the project is published as a package that others can easily download, install, easily update, and uninstall.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#packaging"}},{"name":"Code-Review","score":1,"reason":"Found 1/9 approved changesets -- score normalized to 1","details":null,"documentation":{"short":"Determines if the project requires human code review before pull requests (aka merge requests) are merged.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#code-review"}},{"name":"Binary-Artifacts","score":10,"reason":"no binaries found in the repo","details":null,"documentation":{"short":"Determines if the project has generated executable (binary) artifacts in the source repository.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#binary-artifacts"}},{"name":"Dangerous-Workflow","score":10,"reason":"no dangerous workflow patterns detected","details":null,"documentation":{"short":"Determines if the project's GitHub Action workflows avoid dangerous patterns.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#dangerous-workflow"}},{"name":"Token-Permissions","score":0,"reason":"detected GitHub workflow tokens with excessive permissions","details":["Warn: jobLevel 'contents' permission set to 'write': .github/workflows/push_gem.yml:17","Warn: no topLevel permission defined: .github/workflows/ci.yml:1","Info: topLevel 'contents' permission set to 'read': .github/workflows/push_gem.yml:9"],"documentation":{"short":"Determines if the project's workflows follow the principle of least privilege.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#token-permissions"}},{"name":"Maintained","score":0,"reason":"0 commit(s) and 0 issue activity found in the last 90 days -- score normalized to 0","details":null,"documentation":{"short":"Determines if the project is \"actively maintained\".","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#maintained"}},{"name":"Pinned-Dependencies","score":10,"reason":"all dependencies are pinned","details":["Info:   3 out of   3 GitHub-owned GitHubAction dependencies pinned","Info:   5 out of   5 third-party GitHubAction dependencies pinned"],"documentation":{"short":"Determines if the project has declared and pinned the dependencies of its build process.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#pinned-dependencies"}},{"name":"CII-Best-Practices","score":0,"reason":"no effort to earn an OpenSSF best practices badge detected","details":null,"documentation":{"short":"Determines if the project has an OpenSSF (formerly CII) Best Practices Badge.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#cii-best-practices"}},{"name":"Security-Policy","score":0,"reason":"security policy file not detected","details":["Warn: no security policy file detected","Warn: no security file to analyze","Warn: no security file to analyze","Warn: no security file to analyze"],"documentation":{"short":"Determines if the project has published a security policy.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#security-policy"}},{"name":"Fuzzing","score":0,"reason":"project is not fuzzed","details":["Warn: no fuzzer integrations found"],"documentation":{"short":"Determines if the project uses fuzzing.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#fuzzing"}},{"name":"License","score":10,"reason":"license file detected","details":["Info: project has a license file: LICENSE.txt:0","Info: FSF or OSI recognized license: MIT License: LICENSE.txt:0"],"documentation":{"short":"Determines if the project has defined a license.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#license"}},{"name":"Vulnerabilities","score":10,"reason":"0 existing vulnerabilities detected","details":null,"documentation":{"short":"Determines if the project has open, known unfixed vulnerabilities.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#vulnerabilities"}},{"name":"Signed-Releases","score":-1,"reason":"no releases found","details":null,"documentation":{"short":"Determines if the project cryptographically signs release artifacts.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#signed-releases"}},{"name":"Branch-Protection","score":5,"reason":"branch protection is not maximal on development and all release branches","details":["Info: 'allow deletion' disabled on branch 'master'","Info: 'force pushes' disabled on branch 'master'","Warn: 'branch protection settings apply to administrators' is disabled on branch 'master'","Info: 'stale review dismissal' is required to merge on branch 'master'","Warn: required approving review count is 1 on branch 'master'","Warn: codeowners review is not required on branch 'master'","Warn: 'last push approval' is disabled on branch 'master'","Warn: no status checks found to merge onto branch 'master'","Info: PRs are required in order to make changes on branch 'master'"],"documentation":{"short":"Determines if the default and release branches are protected with GitHub's branch protection settings.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#branch-protection"}},{"name":"SAST","score":0,"reason":"SAST tool is not run on all commits -- score normalized to 0","details":["Warn: 0 commits out of 25 are checked with a SAST tool"],"documentation":{"short":"Determines if the project uses static code analysis.","url":"https://github.com/ossf/scorecard/blob/f6ed084d17c9236477efd66e5b258b9d4cc7b389/docs/checks.md#sast"}}]},"last_synced_at":"2025-08-21T02:27:38.615Z","repository_id":29738516,"created_at":"2025-08-21T02:27:38.615Z","updated_at":"2025-08-21T02:27:38.615Z"},"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":344872684,"owners_count":38361896,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-10-03T21:59:58.778Z","status":"online","status_checked_at":"2026-10-19T02:00:06.414Z","response_time":53,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["activerecord","jsonb","jsonb-accessor","postgres","query","ruby"],"created_at":"2024-08-06T08:02:31.736Z","updated_at":"2026-10-19T16:40:58.953Z","avatar_url":"https://github.com/madeintandem.png","language":"Ruby","funding_links":[],"categories":["Ruby"],"sub_categories":[],"readme":"# JSONb Accessor\n\nCreated by \u0026nbsp;\u0026nbsp;\u0026nbsp; [\u003cimg src=\"https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/tandem-logo.png\" alt=\"Tandem Logo\" /\u003e](https://www.madeintandem.com/)\n\n[![Gem Version](https://badge.fury.io/rb/jsonb_accessor.svg)](http://badge.fury.io/rb/jsonb_accessor) \u0026nbsp;\u0026nbsp;\u0026nbsp;![CI](https://github.com/madeintandem/jsonb_accessor/actions/workflows/ci.yml/badge.svg) \u003cimg src=\"https://raw.githubusercontent.com/madeintandem/jsonb_accessor/master/json-bee.png\" alt=\"JSONb Accessor Logo\" align=\"right\" /\u003e\n\nAdds typed `jsonb` backed fields as first class citizens to your `ActiveRecord` models. This gem is similar in spirit to [HstoreAccessor](https://github.com/madeintandem/hstore_accessor), but the `jsonb` column in PostgreSQL has a few distinct advantages, mostly around nested documents and support for collections.\n\nIt also adds generic scopes for querying `jsonb` columns.\n\n## ⚠️ Status\n\nThis gem is in maintenance mode and no active development of new features is planned. The major focus is to keep it working with new Ruby/Rails versions and fix any bugs reported. Any PRs for feature requests or enhancements will be reviewed and merged -- so contributions are encouraged!\n\n## Table of Contents\n\n- [Installation](#installation)\n- [Usage](#usage)\n- [Scopes](#scopes)\n- [Single-Table Inheritance](#single-table-inheritance)\n- [Dependencies](#dependencies)\n- [Validations](#validations)\n- [Upgrading](#upgrading)\n- [Development](#development)\n- [Contributing](#contributing)\n\n## Installation\n\nAdd this line to your application's `Gemfile`:\n\n```ruby\ngem \"jsonb_accessor\"\n```\n\nAnd then execute:\n\n    $ bundle install\n\n## Usage\n\nFirst we must create a model which has a `jsonb` column available to store data into it:\n\n```ruby\nclass CreateProducts \u003c ActiveRecord::Migration\n  def change\n    create_table :products do |t|\n      t.jsonb :data\n    end\n  end\nend\n```\n\nWe can then declare the `jsonb` fields we wish to expose via the accessor:\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data,\n    title: :string,\n    external_id: :integer,\n    reviewed_at: :datetime\nend\n```\n\nAny type the [`attribute` API](http://api.rubyonrails.org/classes/ActiveRecord/Attributes/ClassMethods.html#method-i-attribute) supports. You can also implement your own type by following the example in the `attribute` documentation.\n\nTo pass through options like `default` and `array` to the `attribute` API, just put them in an array.\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data,\n    title: [:string, default: \"Untitled\"],\n    previous_titles: [:string, array: true, default: []]\nend\n```\n\nThe `default` option works pretty much as you would expect in practice; if no values are set for the attributes, a hash of the specified default values is saved to the jsonb column.\n\nYou can also pass in a `store_key` option.\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data, title: [:string, store_key: :t]\nend\n```\n\nThis allows you to use `title` for your getters and setters, but use `t` as the key in the `jsonb` column.\n\n```ruby\nproduct = Product.new(title: \"Foo\")\nproduct.title #=\u003e \"Foo\"\nproduct.data #=\u003e { \"t\" =\u003e \"Foo\" }\n```\n\nYou can also pass in a `prefix` or `suffix` option.\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data,\n    title: [:string, prefix: :data],\n    external_id: [:integer, suffix: :attr]\nend\n```\n\nThis allows you to use `data_title` and `external_id_attr` for your getters and setters, but use `title` and `external_id` as the key in the `jsonb`.\nAlso, you can pass `true` as a value for `prefix` or `suffix` to use the json_accessor name.\n\n```ruby\nproduct = Product.new(data_title: \"Foo\", external_id_attr: 12314122)\nproduct.data_title #=\u003e \"Foo\"\nproduct.external_id_attr #=\u003e 12314122\nproduct.data #=\u003e { \"title\" =\u003e \"Foo\", \"external_id\" =\u003e 12314122 }\n```\n\n### Global Options\n\nYou can apply options to all fields by passing an options hash as the second parameter:\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data, { prefix: true },\n    title: :string,\n    external_id: :integer,\n    price: :decimal\nend\n```\n\nThis applies the `prefix` to all fields. You can still override it for individual fields:\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data, { prefix: :product },\n    title: :string,\n    external_id: [:integer, prefix: :custom],\n    price: :decimal\nend\n\nproduct = Product.new(product_title: \"Widget\", custom_external_id: 123, product_price: 19.99)\nproduct.product_title #=\u003e \"Widget\"\nproduct.custom_external_id #=\u003e 123\nproduct.product_price #=\u003e 19.99\nproduct.data #=\u003e { \"title\" =\u003e \"Widget\", \"external_id\" =\u003e 123, \"price\" =\u003e 19.99 }\n```\n\nGlobal options currently support `:prefix` and `:suffix`.\n\n## Scopes\n\nJsonb Accessor provides several scopes to make it easier to query `jsonb` columns. `jsonb_contains`, `jsonb_number_where`, `jsonb_time_where`, and `jsonb_where` are available on all `ActiveRecord::Base` subclasses and don't require that you make use of the `jsonb_accessor` declaration.\n\nIf a class does have a `jsonb_accessor` declaration, then we define one custom scope. So, let's say we have a class that looks like this:\n\n```ruby\nclass Product \u003c ActiveRecord::Base\n  jsonb_accessor :data,\n    name: :string,\n    price: [:integer, store_key: :p],\n    price_in_cents: :integer,\n    reviewed_at: :datetime\nend\n```\n\nJsonb Accessor will add a `scope` to `Product` called like the json column with `_where` suffix, in our case `data_where`.\n\n```ruby\nProduct.all.data_where(name: \"Granite Towel\", price: 17)\n```\n\nSimilarly, it will also add a `data_where_not` `scope` to `Product`.\n\n```ruby\nProduct.all.data_where_not(name: \"Plasma Fork\")\n```\n\nFor number fields you can query using `\u003c` or `\u003e`or use plain english if that's what you prefer.\n\n```ruby\nProduct.all.data_where(price: { \u003c: 15 })\nProduct.all.data_where(price: { \u003c=: 15 })\nProduct.all.data_where(price: { less_than: 15 })\nProduct.all.data_where(price: { less_than_or_equal_to: 15 })\n\nProduct.all.data_where(price: { \u003e: 15 })\nProduct.all.data_where(price: { \u003e=: 15 })\nProduct.all.data_where(price: { greater_than: 15 })\nProduct.all.data_where(price: { greater_than_or_equal_to: 15 })\n\nProduct.all.data_where(price: { greater_than: 15, less_than: 30 })\n```\n\nFor time related fields you can query using `before` and `after`.\n\n```ruby\nProduct.all.data_where(reviewed_at: { before: Time.current.beginning_of_week, after: 4.weeks.ago })\n```\n\nIf you want to search for records within a certain time, date, or number range, just pass in the range (Note: this is just shorthand for the above mentioned `before`/`after`/`less_than`/`less_than_or_equal_to`/`greater_than_or_equal_to`/etc options).\n\n```ruby\nProduct.all.data_where(price: 10..20)\nProduct.all.data_where(price: 10...20)\nProduct.all.data_where(reviewed_at: Time.current..3.days.from_now)\n```\n\nThis scope is a convenient wrapper around the `jsonb_where` `scope` that saves you from having to convert the given keys to the store keys and from specifying the column.\n\n### `jsonb_where`\n\nWorks just like the [`scope` above](#scopes) except that it does not convert the given keys to store keys and you must specify the column name. For example:\n\n```ruby\nProduct.all.jsonb_where(:data, reviewed_at: { before: Time.current }, p: { greater_than: 5 })\n\n# instead of\n\nProduct.all.data_where(reviewed_at: { before: Time.current }, price: { greater_than: 5 })\n```\n\nThis scope makes use of the `jsonb_contains`, `jsonb_number_where`, and `jsonb_time_where` `scope`s.\n\n### `jsonb_where_not`\n\nJust the opposite of `jsonb_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).\n\n```ruby\nProduct.all.jsonb_where_not(:data, reviewed_at: { before: Time.current }, p: { greater_than: 5 })\n```\n\n### `\u003cjsonb_attribute\u003e_order`\n\nOrders your query according to values in the Jsonb Accessor fields similar to ActiveRecord's `order`.\n\n```ruby\nProduct.all.data_order(:price)\nProduct.all.data_order(:price, :reviewed_at)\nProduct.all.data_order(:price, reviewed_at: :desc)\n```\n\nIt will convert your given keys into store keys if necessary.\n\n### `jsonb_order`\n\nAllows you to order by a Jsonb Accessor field.\n\n```ruby\nProduct.all.jsonb_order(:data, :price, :asc)\nProduct.all.jsonb_order(:data, :price, :desc)\n```\n\n### `jsonb_contains`\n\nReturns all records that contain the given JSON paths.\n\n```ruby\nProduct.all.jsonb_contains(:data, title: \"foo\")\nProduct.all.jsonb_contains(:data, reviewed_at: 10.minutes.ago, p: 12) # Using the store key\n```\n\n**Note:** Under the hood, `jsonb_contains` uses the [`@\u003e` operator in Postgres](https://www.postgresql.org/docs/9.5/static/functions-json.html) so when you include an array query, the stored array and the array used for the query do not need to match exactly. For example, when queried with `[1, 2]`, records that have arrays of `[2, 1, 3]` will be returned.\n\n### `jsonb_excludes`\n\nReturns all records that exclude the given JSON paths. Pretty much the opposite of `jsonb_contains`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).\n\n```ruby\nProduct.all.jsonb_excludes(:data, title: \"foo\")\nProduct.all.jsonb_excludes(:data, reviewed_at: 10.minutes.ago, p: 12) # Using the store key\n```\n\n### `jsonb_number_where`\n\nReturns all records that match the given criteria.\n\n```ruby\nProduct.all.jsonb_number_where(:data, :price_in_cents, :greater_than, 300)\n```\n\nIt supports:\n\n- `\u003e`\n- `\u003e=`\n- `greater_than`\n- `greater_than_or_equal_to`\n- `\u003c`\n- `\u003c=`\n- `less_than`\n- `less_than_or_equal_to`\n\nand it is indifferent to strings/symbols.\n\n### `jsonb_number_where_not`\n\nReturns all records that do not match the given criteria. It's the opposite of `jsonb_number_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).\n\n```ruby\nProduct.all.jsonb_number_where_not(:data, :price_in_cents, :greater_than, 300)\n```\n\n### `jsonb_time_where`\n\nReturns all records that match the given criteria.\n\n```ruby\nProduct.all.jsonb_time_where(:data, :reviewed_at, :before, 2.days.ago)\n```\n\nIt supports `before` and `after` and is indifferent to strings/symbols.\n\n### `jsonb_time_where_not`\n\nReturns all records that match the given criteria. The opposite of `jsonb_time_where`. Note that this will automatically exclude all records that contain `null` in their jsonb column (the `data` column, in the example below).\n\n```ruby\nProduct.all.jsonb_time_where_not(:data, :reviewed_at, :before, 2.days.ago)\n```\n\n## Single-Table Inheritance\n\nOne of the big issues with `ActiveRecord` single-table inheritance (STI)\nis sparse columns. Essentially, as sub-types of the original table\ndiverge further from their parent more columns are left empty in a given\ntable. Postgres' `jsonb` type provides part of the solution in that\nthe values in an `jsonb` column does not impose a structure - different\nrows can have different values.\n\nWe set up our table with an `jsonb` field:\n\n```ruby\n# db/migration/\u003ctimestamp\u003e_create_players.rb\nclass CreateVehicles \u003c ActiveRecord::Migration\n  def change\n    create_table :vehicles do |t|\n      t.string :make\n      t.string :model\n      t.integer :model_year\n      t.string :type\n      t.jsonb :data\n    end\n  end\nend\n```\n\nAnd for our models:\n\n```ruby\n# app/models/vehicle.rb\nclass Vehicle \u003c ActiveRecord::Base\nend\n\n# app/models/vehicles/automobile.rb\nclass Automobile \u003c Vehicle\n  jsonb_accessor :data,\n    axle_count: :integer,\n    weight: :float\nend\n\n# app/models/vehicles/airplane.rb\nclass Airplane \u003c Vehicle\n  jsonb_accessor :data,\n    engine_type: :string,\n    safety_rating: :integer\nend\n```\n\nFrom here any attributes specific to any sub-class can be stored in the\n`jsonb` column avoiding sparse data. Indices can also be created on\nindividual fields in an `jsonb` column.\n\nThis approach was originally conceived by Joe Hirn in [this blog\npost](https://madeintandem.com/blog/2013-3-single-table-inheritance-hstore-lovely-combination/).\n\n## Validations\n\nBecause this gem promotes attributes nested into the JSON column to first level attributes, most validations should just work. Please leave us feedback if they're not working as expected.\n\n## Dependencies\n\nWe actively test the following in CI, older versions may work but are **not** supported:\n\n- Ruby \u003e= 3.2 or JRuby \u003e= 9.4\n- Rails \u003e= 6.1\n- PostgreSQL \u003e= 13\n\nJRuby isn't fully supported due to errors, see the CI matrix -- contributions to improve support are welcome!\n\n## Development\n\nAfter checking out the repo, run `bin/setup` to install dependencies (make sure postgres is running first).\n\nRun `bin/console` for an interactive prompt that will allow you to experiment.\n\n`rake` will run Rubocop and the specs.\n\n## Contributing\n\n1. [Fork it](https://github.com/madeintandem/jsonb_accessor/fork)\n2. Create your feature branch (`git checkout -b my-new-feature`)\n3. Add tests and changes (run the tests with `rake`)\n4. Commit your changes (`git commit -am 'Add some feature'`)\n5. Push to the branch (`git push origin my-new-feature`)\n6. Create a new Pull Request\n\n## Alternatives\n\n- https://github.com/DmitryTsepelev/store_model 💪\n- https://github.com/palkan/store_attribute ❤️\n- https://github.com/jrochkind/attr_json 🤩\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadeintandem%2Fjsonb_accessor","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fmadeintandem%2Fjsonb_accessor","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fmadeintandem%2Fjsonb_accessor/lists"}