Skip to content

Instantly share code, notes, and snippets.

@Aevin1387
Created June 6, 2013 21:14
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Aevin1387/5725019 to your computer and use it in GitHub Desktop.
Save Aevin1387/5725019 to your computer and use it in GitHub Desktop.
Modify hstore accessor to allow some typing
module HstoreAccessor
def self.included(base)
base.extend(ClassMethods)
end
VALID_TYPES = [:string, :integer, :float, :array, :hash]
SERIALIZERS = {
:array => ->(val) { val.to_json },
:hash => ->(val) { val.to_json }
}
DESERIALIZERS = {
:array => ->(val) { JSON.parse(val) },
:hash => ->(val) { JSON.parse(val) },
:integer => ->(val) { val.to_i },
:float => ->(val) { val.to_f }
}
InvalidDataTypeError = Class.new(StandardError)
module ClassMethods
def hstore_accessor(hstore_attribute, fields)
fields.each do |key, type|
raise InvalidDataTypeError unless VALID_TYPES.include?(type)
define_method("#{key}=") do |value|
serialized_value = value.to_s
if SERIALIZERS.has_key? type
serialized_value = SERIALIZERS[type].call(value)
end
send("#{hstore_attribute}=", (send(hstore_attribute) || {}).merge(key.to_s => serialized_value))
send("#{hstore_attribute}_will_change!")
end
define_method(key) do
deserialized_value = value = send(hstore_attribute) && send(hstore_attribute)[key.to_s]
if DESERIALIZERS.has_key? type
deserialized_value = DESERIALIZERS[type].call(value)
end
deserialized_value
end
send(:scope, "for_#{key}", -> value { where("#{hstore_attribute} -> '#{key}'=?", value.to_s)})
end
end
end
end
ActiveRecord::Base.send(:include, HstoreAccessor)
class Car < Vehicle
hstore_accessor :data,
exterior_color: :integer,
interior_color: :string,
transmission: :string,
drive_type: :string,
fuel_type: :hash,
door_count: :integer,
car_type: :string,
options: :array
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment