J'ai un modèle / table avec une colonne json comme suit
def key1
options['details']&.[]('key1')
end
def key1=(value)
options['details'] ||= {}
options['details']['key1'] ||=0
options['details']['key1'] += value
end
La colonne peut contenir de nombreuses clés, quelque chose comme ça
options = {"details" : {key1: "Value1", key2: "Value2"}}
3 Réponses :
Utiliser la création de méthode dynamique:
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
define_method "# {key} =", la valeur do doit être define_method "# {key} =" do | value | sinon une bonne réponse. Sinon, -> (_, _) {{}} pourrait être remplacé par proc {{}} pour rendre la réponse moins cryptique, mais ce n'est qu'une question de goût personnel .
Je viens également de réaliser que vous ne pouvez pas accéder aux options dans le contexte de la classe, uniquement dans le contexte de l'instance. Cela signifie que cette ligne entraînerait une erreur: options ['details']. Default_proc = -> (_, _) {{}}
@JohanWentholt Merci pour do | value | , bien sûr, mis à jour. Pour le reste: je ne me suis jamais engagé à écrire le code gratuitement. Je viens de montrer la solution de travail. Où mettre l'initialisation (initialiseur?) Appartient à OP.
Vous pouvez également transmettre la clé en tant que paramètre, n'est-ce pas?
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
Comment cela répond-il à une question sur la création de getters et de setters?
En fonction de la réutilisation, vous pouvez choisir différentes options. L'option courte est de définir simplement les méthodes en utilisant une boucle en combinaison avec #define_method .
class SomeModel < ApplicationRecord extend OptionDetailsAttributeAccessors option_details_attr_accessor :key1, :key2 end
Sinon, vous pouvez écrire un module qui fournit ci-dessus comme aides. Un module simple pourrait ressembler à ceci:
# 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
Maintenant, vous pouvez simplement étendre votre classe avec ces aides et ajouter facilement des lecteurs / rédacteurs.
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
options ['details'] &. [] ('key1')Manière intelligente d'utiliser l'opérateur sûr!@Tom serait une façon intelligente d'utiliser
Hash # default_proc:)@AlekseiMatiushkin Oui, ce serait un moyen. L'utilisation de la forme longue de
Hash # []pour que l'opérateur sûr puisse être utilisé montre une bonne compréhension de Ruby. Je voulais le souligner comme un petit truc sympa auquel on ne penserait généralement pas.