存储嵌套JSON的访问器

Mic*_*tor 19 activerecord json ruby-on-rails jsonb

我有"组织"模型,它存储与组织相关的所有信息.有一个名为"集成"的JSONB类型的字段,用于存储与组织具有的所有外部服务集成有关的信息.

如何使用存储访问器访问存储在嵌套JSON中的信息,例如:

{
 "mailchimp": {"api_key":"vsvsvef", "list_id":"12345"},
 "sendgrid" : {"username":"msdvsv", "password":"123456"}
}
Run Code Online (Sandbox Code Playgroud)

我知道我可以使用这样的商店访问器访问mailchimp:

store_accessor :integrations, :mailchimp
Run Code Online (Sandbox Code Playgroud)

如何轻松访问mailchimp的api_key?

two*_*ves 24

你是对的,遗憾的store_accessor是不允许你访问嵌套密钥.原因是它store_accessor基本上只是一个定义getter和setter方法的快捷方式:

# here is a part of store_accessor method code, you can take a look at
# full implementation at
# http://apidock.com/rails/ActiveRecord/Store/ClassMethods/store_accessor
_store_accessors_module.module_eval do
  keys.each do |key|
    # here we define a setter for each passed key
    define_method("#{key}=") do |value|
      write_store_attribute(store_attribute, key, value)
    end

    # and here goes the getter
    define_method(key) do
      read_store_attribute(store_attribute, key)
    end
  end
end
Run Code Online (Sandbox Code Playgroud)

那么,你的选择是:

  1. 手动实现自己的getter和setter方法集:

    # somewhere in your model
    def mailchimp_api_key
      self.mailchimp["api_key"]
    end
    
    def mailchimp_api_key= value
      self.mailchimp["api_key"] = value
    end
    
    Run Code Online (Sandbox Code Playgroud)

    这解决了一个问题,但是您必须为每个嵌套属性重复编写大量内容.

  2. ActiveRecord::Store::ClassMethods模块内部编写自己的帮助器方法,该方法将为您传入的属性集动态定义相同的setter和getter方法.您必须采用Rails的基本实现store_accessor并向其添加额外的哈希键迭代.不确定这是否会变得简单,但看到共享为宝石肯定会很有趣.

  3. 保留Rails本身并使用postgres json类型支持的强大功能和一些纯SQL代码.例如,您可以使用以下内容访问api_key属性:

    SELECT integrations->'mailchimp'->>'api_key' as mailchimp_api_key FROM your_table_name;
    
    Run Code Online (Sandbox Code Playgroud)

    有关postgres json查询的更多信息,请点击此处.


mag*_*ni- 10

您可以使用属性 API来执行此操作

store_accessor :integrations, :mailchimp
store_accessor :mailchimp, :api_key, :list_id
attribute :mailchimp, :json # :jsonb also works if you're using a PG column of that type for `integrations`
Run Code Online (Sandbox Code Playgroud)