ruby 在Rails中获取和设置json列的键的整洁方法

tquggr8v  于 2024-01-07  发布在  Ruby
关注(0)|答案(4)|浏览(102)

我有一个模型/表,其中包含一个JSON列,如下所示

t.json :options, default: {}

字符串
列中可以包含许多键,类似于

options = {"details" : {key1: "Value1", key2: "Value2"}}


我想轻松地设置和获取这些值。所以我做了getter和setter。

def key1
  options['details']&.[]('key1')
end

def key1=(value)
  options['details'] ||= {}
  options['details']['key1'] ||=0 
  options['details']['key1'] += value 
end


但这只是增加了代码行,当添加更多细节时,它不会扩展。你能建议一个干净整洁的方法吗?

rryofs0p

rryofs0p1#

使用动态方法创建:

options['details'].default_proc = ->(_,_) {{}}
ALLOWED_KEYS = %i[key1 key2 key3]

ALLOWED_KEYS.each do |key|
  define_method key do
    options['details'][key] if options['details'].key?(key)
  end
  define_method "#{key}=" do |value|
    (options['details'][key] ||= 0) += value
  end
end

字符串

nlejzf6q

nlejzf6q2#

你也可以把键作为参数传递,对吗?

def get_key key=:key1
   options['details']&.[](key)
  end

  def set_key= value, key=:key1
   options['details'] ||= {}
   options['details'][key] ||=0 
   options['details'][key] += value 
  end

字符串

ngynwnxp

ngynwnxp3#

简单短小

根据可重用性,你可以选择不同的选项。简单的选项是使用循环和#define_method来定义方法。

class SomeModel < ApplicationRecord
  option_accessors = ['key1', 'key2']

  option_accessors.map(&:to_s).each do |accessor_name|
    #                     ^ in case you provide symbols in option_accessors
    #                       this can be left out if know this is not the case

    define_method accessor_name do
      options.dig('details', accessor_name)
    end

    define_method "#{accessor_name}=" do |value|
      details = options['details'] ||= {}
      details[accessor_name] ||= 0
      details[accessor_name] += value
    end
  end
end

字符串

编写模块

或者,你可以编写一个模块,提供上述作为帮助程序。一个简单的模块可能看起来像这样:

# app/model_helpers/option_details_attribute_accessors.rb
module OptionDetailsAttributeAccessors
  def option_details_attr_reader(*accessors)
    accessors.map(&:to_s).each do |accessor|
      define_method accessor do
        options.dig('details', accessor)
      end
    end
  end

  def option_details_attr_writer(*accessors)
    accessors.map(&:to_s).each do |accessor|
      define_method "#{accessor}=" do |value|
        details = options['details'] ||= {}
        details[accessor] ||= 0
        details[accessor] += value
      end
    end
  end

  def option_details_attr_accessor(*accessors)
    option_details_attr_reader(*accessors)
    option_details_attr_writer(*accessors)
  end
end


现在你可以简单地用这些helper扩展你的类,并轻松地添加reader/writer。

class SomeModel < ApplicationRecord
  extend OptionDetailsAttributeAccessors

  option_details_attr_accessor :key1, :key2
end


如果有任何不清楚的地方,请在评论中询问。

ozxc1zmp

ozxc1zmp4#

这被引用为一个Phind调用的链接,给了我一个糟糕的答案。我建议store_accessor :column_name是2024年与平面JSON对象接口的最佳方式。
它允许您与JSON列交互,就像它是一个关联一样,例如,

class BusinessProfile < ApplicationRecord
  store_accessor :vcard_details, :website_url, :contacts_array
end

字符串
然后,您可以通过profile.website_url调用示例,并使用profile.website_url = "https://blah.com进行设置

相关问题