web-dev-qa-db-ja.com

ネストされたJSONのストアアクセサー

組織に関連するすべての情報を格納するモデル「組織」を持っています。組織が持つすべての外部サービス統合に関する情報を格納する「統合」という名前のJSONBタイプのフィールドがあります。

ストアアクセサーを使用して、ネストされたJSONに格納されている情報にアクセスするにはどうすればよいですか。

{
 "mailchimp": {"api_key":"vsvsvef", "list_id":"12345"},
 "sendgrid" : {"username":"msdvsv", "password":"123456"}
}

私はこのようなストアアクセサーでmailchimpにアクセスできることを知っています。

store_accessor :integrations, :mailchimp

Mailchimpのapi_keyに簡単にアクセスするにはどうすればよいですか?

20
Michael Victor

残念ながら、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

したがって、ここでのオプションは次のとおりです。

  1. 独自のゲッターメソッドとセッターメソッドのセットを手動で実装するには:

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

    これで問題は解決しますが、ネストされた属性ごとにこれを何度も書く必要があります。

  2. ActiveRecord::Store::ClassMethodsモジュール内に独自のヘルパーメソッドを記述して、渡した一連の属性に対して動的に同じセッターメソッドとゲッターメソッドを定義します。Rails store_accessorそして、それにハッシュキーの反復を追加します。これが簡単なものになるかどうかはわかりませんが、gemとして共有されるのを見るのは間違いなく興味深いでしょう。

  3. Rails自体を残して、いくつかの純粋なjsonコードでpostgres SQL型のサポートを使用します。たとえば、api_key属性にアクセスするにはそんな感じ:

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

    Postgres jsonクエリの詳細については、 ここ を参照してください。

24
twonegatives

同じものを探していました。 @twonegativesが示すように、store_accessorは役に立ちません。しかし、データを取得するために#Digメソッドがかなりうまく機能することがわかりました。そう...

#somewhere in Organization model
def api_key
  integrations.Dig("mailchimp", "api_key")
end

def username
  integrations.Dig("sendgrid", "username")
end
1
spflow