I have a model ProjectKeyword where I use jsonb datatype in the column :segemnted_data
class ProjectKeyword < ApplicationRecord belongs_to :project belongs_to :keyword has_many :project_keyword_dimensions has_many :dimensions, through: :project_keyword_dimensions validates :project_id, :keyword_id, presence: true end
Migration
class AddSegemtnedDataToProjectKeywords < ActiveRecord::Migration[5.0] def change add_column :project_keywords, :segmented_data, :jsonb, default: '{}' add_index :project_keywords, :segmented_data, using: :gin end end
My problem is when I create new project_keyword
instance the default value of the segmented_data
is a string not a hash and I cannot update this field or merge with another hash For example
[12] pry(#)> new_pr_keyword = ProjectKeyword.new(project_id: 1671333, keyword_id: 39155) => #<ProjectKeyword:0x007fd997641090 id: nil, project_id: 1671333, keyword_id: 39155, segmented_data: "{}"> [13] pry(#)> new_pr_keyword.save! => true [14] pry(#)> new_pr_keyword.segmented_data.update({'new_data' => 'some_data'}) NoMethodError: undefined method `update' for "{}":String from (pry):14:in `block (3 levels) in <top (required)>'
But when I asign hash
value to the field segmented_data
before update then update
method works fine.
For example
[15] pry(#)> new_pr_keyword.segmented_data = {'new_data' => 'some_data'} => {"new_data"=>"some_data"} [16] pry(#)> new_pr_keyword.save! => true [17] pry(#)> new_pr_keyword.segmented_data.update({'new_data_2' => 'some_data_2'}) => {"new_data"=>"some_data", "new_data_2"=>"some_data_2"} [18] pry(#)> new_pr_keyword.save! => true
The question is how to make default value of segmented_data to be a Hash class not a String so method update then will work straight away on this field, after object just was created.
Json processes input faster than jsonb as there is no conversion involved in this. Jsonb converts the JSON data into the binary form so it has slightly slower input due to the binary conversion overhead. There is no change in the Schema design while working with JSON.
The JSONB data type stores JSON (JavaScript Object Notation) data as a binary representation of the JSONB value, which eliminates whitespace, duplicate keys, and key ordering. JSONB supports GIN indexes.
In general, most applications should prefer to store JSON data as jsonb , unless there are quite specialized needs, such as legacy assumptions about ordering of object keys. RFC 7159 specifies that JSON strings should be encoded in UTF8.
JSONB objects are stored as a decompressed binary as opposed to "raw data" in JSON, where no reparsing of data is required during retrieval. JSONB also supports indexing, which can be a significant advantage.
This has worked for me on several projects:
add_column :project_keywords, :segmented_data, :jsonb, default: {}
(not a string, a ruby hash)
I seem to recall this not working on Rails 3, but it should be fine in Rails 4.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With