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.