Class: SerializableAttributes::Schema
- Defined in:
- lib/serializable_attributes/schema.rb
Class Attribute Summary collapse
Instance Attribute Summary collapse
-
#field(type_name, *names) ⇒ Object
readonly
Adds the accessors for a serialized field on this model.
-
#fields ⇒ Object
readonly
Returns the value of attribute fields.
-
#formatter ⇒ Object
Returns the value of attribute formatter.
-
#model ⇒ Object
readonly
Returns the value of attribute model.
Instance Method Summary collapse
- #all_column_names ⇒ Object
- #decode(data, is_new_record = false) ⇒ Object
- #encode(body) ⇒ Object
- #include?(key) ⇒ Boolean
-
#initialize(model, field, options) ⇒ Schema
constructor
Initializes a new Schema.
Constructor Details
#initialize(model, field, options) ⇒ Schema
Initializes a new Schema. See ‘ModelMethods#serialize_attributes`.
model - The ActiveRecord class. field - The String name of the ActiveRecord attribute that holds
data.
options - Optional Hash:
:blob - The String name of the actual DB field. Defaults to
"raw_#{field}"
:formatter - The module that handles encoding and decoding the
data. The default is set in
`Schema#default_formatter`.
64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/serializable_attributes/schema.rb', line 64 def initialize(model, field, ) @model, @field, @fields = model, field, {} @blob_field = .delete(:blob) || "raw_#{@field}" @formatter = .delete(:formatter) || self.class.default_formatter blob_field = @blob_field data_field = @field = class << @model; self; end changed_ivar = "#{data_field}_changed" .send(:attr_accessor, "#{data_field}_schema") @model.send("#{data_field}_schema=", self) @model.class_eval do def reload( = nil) reset_serialized_data super end end .send(:define_method, :attribute_names) do column_names + send("#{data_field}_schema").all_column_names end @model.send(:define_method, :reset_serialized_data) do instance_variable_set("@#{data_field}", nil) end @model.send(:define_method, :attribute_names) do (super() + send(data_field).keys - [blob_field]). map! { |s| s.to_s }.sort! end @model.send(:define_method, :read_attribute) do |attribute_name| schema = self.class.send("#{data_field}_schema") if schema.include?(attribute_name) data[attribute_name.to_s] else super(attribute_name) end end if defined?(ActiveRecord::VERSION) && ActiveRecord::VERSION::STRING >= '3.1' @model.send(:define_method, :attributes) do attributes = super().merge(send(data_field)) attributes.delete blob_field attributes end end @model.send(:define_method, data_field) do instance_variable_get("@#{data_field}") || begin instance_variable_get("@#{changed_ivar}").clear if send("#{changed_ivar}?") schema = self.class.send("#{data_field}_schema") hash = schema.decode(send(blob_field), new_record?) instance_variable_set("@#{data_field}", hash) hash end end @model.send(:define_method, :write_serialized_field) do |name, value| raw_data = send(data_field) # load fields if needed name_str = name.to_s schema = self.class.send("#{data_field}_schema") type = schema.fields[name_str] changed_fields = send(changed_ivar) instance_variable_get("@#{changed_ivar}")[name_str] = raw_data[name_str] unless changed_fields.include?(name_str) parsed_value = type ? type.parse(value) : value if parsed_value.nil? raw_data.delete(name_str) else raw_data[name_str] = parsed_value end parsed_value end @model.send(:define_method, changed_ivar) do hash = instance_variable_get("@#{changed_ivar}") || instance_variable_set("@#{changed_ivar}", {}) hash.keys end @model.send(:define_method, "#{changed_ivar}?") do !send(changed_ivar).empty? end @model.before_save do |r| schema = r.class.send("#{data_field}_schema") if r.send(blob_field).nil? || !r.send(changed_ivar).empty? r.send("#{blob_field}=", schema.encode(r.send(data_field))) end end end |
Class Attribute Details
.default_formatter ⇒ Object
5 6 7 |
# File 'lib/serializable_attributes/schema.rb', line 5 def default_formatter @default_formatter ||= SerializableAttributes::Format::ActiveSupportJson end |
Instance Attribute Details
#field(type_name, *names) ⇒ Object (readonly)
Adds the accessors for a serialized field on this model. Also sets up the encoders and decoders.
type_name - The Symbol matching a valid type. *names - One or more Symbol field names. options - Optional Hash to be sent to the initialized Type.
:default - Sets the default value.
Returns nothing.
165 166 167 |
# File 'lib/serializable_attributes/schema.rb', line 165 def field @field end |
#fields ⇒ Object (readonly)
Returns the value of attribute fields.
11 12 13 |
# File 'lib/serializable_attributes/schema.rb', line 11 def fields @fields end |
#formatter ⇒ Object
Returns the value of attribute formatter.
10 11 12 |
# File 'lib/serializable_attributes/schema.rb', line 10 def formatter @formatter end |
#model ⇒ Object (readonly)
Returns the value of attribute model.
11 12 13 |
# File 'lib/serializable_attributes/schema.rb', line 11 def model @model end |
Instance Method Details
#all_column_names ⇒ Object
13 14 15 |
# File 'lib/serializable_attributes/schema.rb', line 13 def all_column_names fields ? fields.keys : [] end |
#decode(data, is_new_record = false) ⇒ Object
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
# File 'lib/serializable_attributes/schema.rb', line 27 def decode(data, is_new_record = false) decoded = formatter.decode(data) hash = ::Hash.new do |h, key| if type = fields[key] h[key] = type ? type.default : nil end end decoded.each do |k, v| next unless include?(k) type = fields[k] hash[k] = type ? type.parse(v) : v end if decoded.blank? && is_new_record fields.each do |key, type| hash[key] = type.default if type.default end end hash end |
#encode(body) ⇒ Object
17 18 19 20 21 22 23 24 25 |
# File 'lib/serializable_attributes/schema.rb', line 17 def encode(body) body = body.dup body.each do |key, value| if field = fields[key] body[key] = field.encode(value) end end formatter.encode(body) end |
#include?(key) ⇒ Boolean
49 50 51 |
# File 'lib/serializable_attributes/schema.rb', line 49 def include?(key) @fields.include?(key.to_s) end |