Skip to Content Skip to Search
Methods
H

Instance Public methods

has_delegated_json(attr, **schema)

Like has_json but each schema key also becomes its own set of accessor methods.

class Account < ApplicationRecord
  has_delegated_json :flags, beta: false, staff: :boolean
end

a = Account.new
a.beta? # => false
a.beta = true
a.beta # => true
# File activemodel/lib/active_model/schematized_json.rb, line 57
def has_delegated_json(attr, **schema)
  has_json attr, **schema

  schema.keys.each do |schema_key|
    define_method(schema_key)       { public_send(attr).public_send(schema_key) }
    define_method("#{schema_key}?") { public_send(attr).public_send("#{schema_key}?") }
    define_method("#{schema_key}=") { |value| send(attr).public_send("#{schema_key}=", value) }
  end
end

has_json(attr, **schema)

Provides a schema-enforced access object for a JSON attribute. This allows you to assign values directly from the UI as strings, and still have them set with the correct JSON type in the database.

Only the three basic JSON types are supported: boolean, integer, and string. No nesting either. These types can either be set by referring to them by their symbol or by setting a default value. Default values are set when a new model is instantiated and on before_save (if defined).

Examples:

class Account < ApplicationRecord
  has_json :settings, restrict_creation_to_admins: true, max_invites: 10, greeting: "Hello!"
  has_json :flags, beta: false, staff: :boolean
end

a = Account.new
a.settings.restrict_creation_to_admins? # => true
a.settings.max_invites = "100" # => Set to integer 100
a.settings = { "restrict_creation_to_admins" => "false", "max_invites" => "500", "greeting" => "goodbye" }
a.settings.greeting # => "goodbye"
a.flags.staff # => nil
a.flags.staff? # => false
# File activemodel/lib/active_model/schematized_json.rb, line 32
def has_json(attr, **schema)
  define_method(attr) do
    # Ensure the attribute is set if nil, so we can pass the reference to the accessor for defaults.
    _write_attribute(attr.to_s, {}) if attribute(attr.to_s).nil?

    # No memoization used in order to stay compatible with #reload (and because it's such a thin accessor).
    ActiveModel::SchematizedJson::DataAccessor.new(schema, data: attribute(attr.to_s))
  end

  define_method("#{attr}=") { |data| public_send(attr).assign_data_with_type_casting(data) }

  # Ensure default values are set before saving by relying on DataAccessor instantiation to do it.
  before_save -> { send(attr) } if respond_to?(:before_save)
end