【问题标题】:Correct way to define virtual attributes on a Model for the keys in a JSON column in rails在模型上为 Rails 中 JSON 列中的键定义虚拟属性的正确方法
【发布时间】:2016-09-23 05:27:36
【问题描述】:

在我的 rails 模型中,我有一个 JSON 列,用于存储一些元信息。 这将由用户从表单中输入。

由于 JSON 列的键不是模型的属性,我不能直接在 form_for 中使用它们,而是需要定义一个虚拟属性。

由于虚拟属性的数量可能会增长到任意长,我想使用元编程来定义属性。

我确实尝试了this question 中的答案,但是当我在模型中使用该常量时,我​​收到一个错误,指出该常量未定义。所以我直接在数组中添加了键的符号并在模块中迭代它们。当我这样做时,我收到一个错误,提示堆栈级别太深。

有人可以帮我吗?

【问题讨论】:

    标签: ruby ruby-on-rails-4 activerecord metaprogramming


    【解决方案1】:

    如果您使用PostgreSQL 特定列,例如hstorejson,只需使用store_accessor 来生成访问器方法。 请注意,这些列使用字符串键控哈希,不允许使用符号访问。

    class Model < ActiveRecord::Base
      store_accessor :my_json_column, [ :key_1, :key_2, key_3 ]
    end
    

    它在幕后做了什么?它定义了 write\read 辅助方法:

    def store_accessor(store_attribute, *keys)
      keys = keys.flatten
    
      _store_accessors_module.module_eval do
        keys.each do |key|
          define_method("#{key}=") do |value|
            write_store_attribute(store_attribute, key, value)
          end
    
          define_method(key) do
            read_store_attribute(store_attribute, key)
          end
        end
      end
    

    # .....

    store

    【讨论】:

    • 感谢您的回复。我不知道这件事。如果您不介意,请告诉我应该首选哪种方法(store_accessor 或在迭代器中使用define_method)以及为什么?
    • 你应该使用 Rails 和 Rails 核心库提供的方法和宏来避免核心库方法的重复,Rails 代码库具有良好的测试覆盖率。但是您的回答也有利于教育目的。 + 1
    • 优秀的程序员可以编写新代码,忍者程序员可以让旧代码重新工作。
    【解决方案2】:

    我想通了。我将该属性作为 JSON 列的键返回,它现在可以正常工作了。

    # lib/virtuals.rb
    module Virtuals
    
      %W(key_1 key_2 key_3).each do |attr|
        define_method(attr) do
          self.my_json_column[attr]
        end
    
        define_method("#{attr}=") do |val|
          self.my_json_column[attr] = val
        end
      end
    end
    

    在我的模型中,我只需要包含上面的模块,它在form_for 中工作正常,并且更新也正确。

    【讨论】:

      猜你喜欢
      • 2011-03-11
      • 1970-01-01
      • 2023-03-17
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-30
      • 2016-04-07
      相关资源
      最近更新 更多