Akshay Pardhanani Akshay Pardhanani - 2 months ago 14
Ruby Question

Correct way to define virtual attributes on a Model for the keys in a JSON column in rails

In my rails model I have a JSON column which stores some meta information.
This is to be entered bu the user from a form.

Since the keys of the JSON column are not attributes of the model I cannot use them directly in

form_for
instead I need to define a virtual attribute.

Since this number of virtual attributes could grow to be arbitrarily lengthy I would like to use meta programming to define the attributes.

I did try the answer in this question however when I use the constant in my model I get an error saying that the constant is undefined. So I added the symbols for the keys in an array directly and iterate over them in the module. When I do this I get an error that says stack level too deep.

Please can someone help me out here?

Answer

If you are using PostgreSQL specific columns like hstore or json simply use store_accessor instead to generate the accessor methods. Be aware that these columns use a string keyed hash and do not allow access using a symbol.

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

What it doing under the hood? It has define write\read helper methods:

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

Comments