store_accessor with jsonb nesting
So Im building a user permits column with jsonb.
jsonb column
bar_permit: {
key1: [],
key2: "Bar",
key3: false,
key4: false,
key5: false
},
foobar_permit: {
key1: [],
key2: "Bar",
key3: false,
key4: false,
key5: false
}
}
class Foo < ActiveRecord::Base
serialize :permits, HashSerializer
store_accessor :permits, :bar_permit, :foobar_permit
end
with the HashSerializer I can call the first hash keys as table columns
example:
foo.bar_permit
or
foo.foobar_permit
class HashSerializer
def self.dump(hash)
hash.to_json
end
def self.load(hash)
(hash || {}).with_indifferent_access
end
end
now I need to make the bar_permit and the foobar_permit to a hash with preset keys
I add these methods to the model so I can have a {key:value} for bar_permits
def bar_permit=(attributes)
super
value = []
attributes.each do |index, attrs|
value << attrs
end
write_attribute(self.permits[:bar_permit], value)
end
def bar_permit
super
self.permits[:bar_permit]= {
key1: [],
key2: "Bar",
key3: false,
key4: false,
key5: false
}
end
Is this the correct way of making the attributes behave as hash?
How can I make the form helpers work with the keys of the virtual attributes as fields.
Hello,
I will test your script to get a better understand about your first question (is this the correct way),
but, for the second question (How can I make the form helpers work with the keys of the virtual attributes as fields.)
You can use OpenStruct
for this,
ex:
<%= form_for @foo do |f| %>
<%= f.fields_for :permits, OpenStruct.new(@foo.permits) do |permit_fields| %>
<%= permit_fields.text_field :key2 %>
<% end %>
<% end %>
Honestly, I think you're better off using this than trying to build your own implementation. It'll let you set defaults and types for each attribute which will make it significantly easier to work with: https://github.com/devmynd/jsonb_accessor
The types are going to be a problem when you start using forms because they won't automatically be cast to booleans, etc. That makes for a mess.
You shouldn't need the HashSerializer
because that's what store_accessor
implements for you. It doesn't do with indifferent access, but it will convert back and forth from jsonb to a hash.
To set defaults, just setup a default value after initialize:
class Foo < ApplicationRecord
store_accessor :permits, :bar_permit, :baz_permit
after_initialize :set_defaults
def set_defaults
self.permits ||= {
bar_permit: {
key1: [],
key2: "Bar",
key3: false,
key4: false,
key5: false
},
foobar_permit: {
key1: [],
key2: "Bar",
key3: false,
key4: false,
key5: false
}
}
end
end