activerecord-typedstore
activerecord-typedstore copied to clipboard
Add example for usage with Postgres jsonb columns
Just wanted to let you know I had some issues getting this setup when using a Postgres jsonb column...
My first implementation did not include a custom coder, and when updating a typed_store attribute, I got this error:
ActiveRecord::StatementInvalid: PG::InvalidTextRepresentation: ERROR: invalid input syntax for type json
DETAIL: Token "-" is invalid.
CONTEXT: JSON data, line 1: -...
: UPDATE "companies" SET "settings" = $1, "updated_at" = $2 WHERE "companies"."id" = $3
Which is because it was using the default yaml coder.
However, when I added the DumbCoder
, I got a TypeError: can't cast Hash to
error.
It was all solved by just using the JSON coder:
typed_store :settings, coder: JSON do |s|
s.boolean :foo, default: true, null: false
end
I think this would be useful to add to the readme...
Cheers!
+1 @rafaelfranca
But the json string seems escaped with coder: JSON
:/
I'm not a PostgreSQL user. I'm fine with adding it, but to be fair I don't know the solution for the problem so I'd rely on someone sending a PR.
The following JSONB example includes:
- Full example model class
- How to specify the correct coder, including the current
require
workaround needed - How to generate the migration
- An example JSONB query (specific to PostgreSQL)
- A
validates
for one of the accessors with a default value to workaround thecreate!
issue (https://github.com/byroot/activerecord-typedstore/issues/37)
# won't need to do this require in the next release of `activerecord-typedstore`
require 'active_record/typed_store/identity_coder'
class Foo < ApplicationRecord
typed_store :details, coder: ActiveRecord::TypedStore::IdentityCoder do |s|
s.boolean :public, default: false, null: false
s.string :email
s.datetime :publish_at
s.integer :age, null: false
# You can define array attributes like in rails 4 and postgres
s.string :tags, array: true, default: [], null: false
# In addition to prevent null values you can prevent blank values
s.string :title, blank: false, default: 'Title'
# If you don't want to enforce a datatype but still like to have default handling
s.any :source, blank: false, default: 'web'
end
# You can use any ActiveModel validator
validates :age, presence: true
end
Migration:
bin/rails generate migration CreateFoo details:jsonb
Using the class from a console (mine has a name field and timestamps, you can ignore them):