module JsonAttribute::HasJsonAttribute

Public Instance Methods

has_json_attribute(attribute, options = {}) click to toggle source
# File lib/json_attribute/has_json_attribute.rb, line 8
def has_json_attribute(attribute, options = {})
  include JsonAttribute::InstanceMethods

  column = (options[:column] || :json_attribute).to_s
  type = options[:type]
  allow_nil = options[:allow_nil]
  presence = options[:presence]
  default_value = options[:default]

  if table_exists? && !connection.migration_context.needs_migration?
    if !column_names.include?(column)
      raise ColumnNotExist
    end

    if [:jsonb, :json].none?(columns_hash[column].type)
      raise InvalidColumnType
    end
  end

  # getter
  define_method attribute do
    value = get_json_attribute_value_for(attribute, column: column)
    if value.nil?
      default_value.respond_to?(:call) ? default_value.call(self) : default_value
    else
      value
    end
  end

  # setter
  define_method "#{attribute}=" do |value|
    value = type_for_attribute(attribute).serialize(value)
    set_json_attribute_value_for(attribute, value, column: column)
  end

  # validator
  if presence
    validates attribute, presence: true
  end

  if type.present?

    validators = Validators.constants.index_by(&:downcase)
    validator = Validators.const_get(validators[type]) rescue nil

    unless validator
      raise InvalidType.new("type should be one of #{validators.keys}")
    end

    attribute attribute, type

    validate do
      value = public_send(attribute)
      next if value.nil? && allow_nil
      unless validator.call(value)
        self.errors.add(attribute, :invalid)
      end
    end
  end
end