我在Rails应用程序中使用ActiveRecord::ConnectionAdapters::PostgreSQLAdapter
。假设我有一个架构:
create_table "foo", id: :bigserial, force: :cascade do |t|
t.string "name"
t.jsonb "data", null: false
end
现在假设我运行以下代码:
class Foo < ActiveRecord::Base
self.table_name = :foo
end
my_foo = Foo.create!(:name => 'foobar', :data => {:a => 'hello'})
my_foo = Foo.where(:name => 'foobar').first!
puts my_foo.data[:a]
puts my_foo.data['a']
输出结果为:
# nil
# 'hello'
是否可以让ActiveRecord使用HashWithIndifferentAccess自动反序列化jsonb类型?
答案 0 :(得分:10)
|您可以使用自定义序列化程序,以便也可以使用符号访问JSON对象。
# app/models/user.rb
class User < ActiveRecord::Base
serialize :preferences, HashSerializer
end
# app/serializers/hash_serializer.rb
class HashSerializer
def self.dump(hash)
hash
end
def self.load(hash)
(hash || {}).with_indifferent_access
end
end
完全信用 - 没有谷歌搜索 - 转到http://nandovieira.com/using-postgresql-and-jsonb-with-ruby-on-rails。
答案 1 :(得分:1)
如果您的根对象是一个数组,则需要稍微不同地处理它。
排名5 +
class User < ActiveRecord::Base
serialize :preferences, HashSerializer
serialize :some_list, ArrayHashSerializer
end
class HashSerializer
def self.dump(hash)
hash
end
def self.load(hash)
(hash || {}).with_indifferent_access
end
end
class ArrayHashSerializer
def self.dump(array)
array
end
def self.load(array)
(array || []).map(&:with_indifferent_access)
end
end
路轨<= 4
class User < ActiveRecord::Base
serialize :preferences, HashSerializer
serialize :some_list, ArrayHashSerializer
end
class HashSerializer
def self.dump(hash)
hash.to_json
end
def self.load(hash)
(hash || {}).with_indifferent_access
end
end
class ArrayHashSerializer
def self.dump(array)
array.to_json
end
def self.load(array)
(array || []).map(&:with_indifferent_access)
end
end
答案 2 :(得分:0)
在 rails 6 中,我在其中一些答案中遇到错误 - 特别是 with_indifferent_access 方法。
这是我最后的结果:
#in models/user.rb - role is a jsonb column
class User
serialize :role, ApplicationHelper::JsonbIndifferentSerializer
end
#in helpers/application_helper.rb - probably not best practive to put it here
#but for a simple class I didn't want to add a whole folder under /app
class JsonbIndifferentSerializer
def self.dump(obj)
obj.to_json
end
def self.load(str_json)
hsh = JSON.load(str_json) if str_json.class == String
HashWithIndifferentAccess.new(hsh)
end
end