【问题标题】:Is there a way to serialize ActiveRecord's JSON properties using HashWithIndifferentAccess?有没有办法使用 HashWithIndifferentAccess 序列化 ActiveRecord 的 JSON 属性?
【发布时间】:2015-04-25 06:53:11
【问题描述】:

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

【问题讨论】:

  • 如果没有更好的办法,def data; HashWithIndifferentAccess.new(super); end 是一种解决方法。
  • @muistooshort 另一种说法是super.with_indifferent_access

标签: ruby-on-rails ruby json activerecord


【解决方案1】:

|您可以使用自定义序列化程序,这样您也可以使用符号访问 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

【讨论】:

  • 为了让它在 Rails 5 中工作,我删除了 #to_jsonhash 中的 .dump 调用。
  • 谢谢@JoeMasilotti!
  • 对于未来的谷歌员工:您还可以在.dump 中添加明确的#as_json 调用hash,更明确一点
【解决方案2】:

如果你的根对象是一个数组,你需要稍微不同地处理它。

Rails 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

导轨

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

【讨论】:

    【解决方案3】:

    在 rails 6 中,我遇到了其中一些答案的错误 - 特别是 with_indiffergent_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
    

    【讨论】:

      猜你喜欢
      • 2011-04-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-08-25
      • 2019-10-27
      相关资源
      最近更新 更多