Store accessor for nested JSON

后端 未结 2 942
甜味超标
甜味超标 2021-02-12 11:28

I have the model \"Organization\" that stores all information related to an organization. There is a field of type JSONB named \"integrations\" that stores information pertainin

相关标签:
2条回答
  • 2021-02-12 12:05

    I was looking for the same thing. As @twonegatives indicated, store_accessor won't help us. But I did find the #dig method to work pretty well for getting the data. So...

    #somewhere in Organization model
    def api_key
      integrations.dig("mailchimp", "api_key")
    end
    
    def username
      integrations.dig("sendgrid", "username")
    end
    
    0 讨论(0)
  • 2021-02-12 12:18

    You're right, unfortunately store_accessor does not allow you to access nested keys. The reason is that store_accessor is basically just a shortcut which defines getter and setter methods:

    # 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
    

    So, your options here are:

    1. To implement your own set of getter and setter methods manually:

      # somewhere in your model
      def mailchimp_api_key
        self.mailchimp["api_key"]
      end
      
      def mailchimp_api_key= value
        self.mailchimp["api_key"] = value
      end
      

      This solves a problem, but you'd have to write lots of this repeatedly for each of nested attributes.

    2. To write your own helper method inside of ActiveRecord::Store::ClassMethods module which would define the same setter and getter methods dynamically for the set of attributes you pass in. You'd have to take the basic implementation of Rails store_accessor and add an additional hash keys iteration to it. Not sure if this is going to be an easy one, but would definitely be interesting to see shared as a gem.

    3. Leave Rails itself and use the power of postgres json type support with some pure SQL code. For example, you can access api_key attribute with something like that:

      SELECT integrations->'mailchimp'->>'api_key' as mailchimp_api_key FROM your_table_name;
      

      More on postgres json queries can be found here.

    0 讨论(0)
提交回复
热议问题