有没有办法使用HashWithIndifferentAccess序列化ActiveRecord的JSON属性?

时间:2015-02-23 20:05:10

标签: ruby-on-rails ruby json activerecord

我在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类型?

3 个答案:

答案 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