module ModelOrchestration::Base

The module containing the base functionality. This includes class methods to specify nested models and dependencies, as well as ActiveModel-like functionality, such as attribute accessors for the nested models and validation methods.

Public Class Methods

new(attrs = {}) click to toggle source

Instantiate the model and all nested models. Attributes can be submitted as a hash and will be handed over to the nested models.

# File lib/model_orchestration/base.rb, line 119
def initialize(attrs = {})
  @nested_model_instances = {}

  self._nested_models.each do |model|
    model_class = model.to_s.classify.constantize
  
    if attrs.include?(model)
      @nested_model_instances[model] = initialize_nested_model(model_class, attrs[model])
    else
      @nested_model_instances[model] = initialize_nested_model(model_class)
    end
  end

  self._dependencies.each do |from, tos|
    tos.each do |to|
      @nested_model_instances[from].public_send("#{to.to_s}=", @nested_model_instances[to])
    end
  end
end

Public Instance Methods

[](key) click to toggle source

Get a nested model by name (symbol).

class Signup
  include ModelOrchestration::Base

  nested_model :company
  nested_model :employee

  nested_model_dependency from: :employee, to: :company
end

signup  = Signup.new
company = signup[:company]

Because ActiveRecord classes also support the +[]+ method, it can be chained to get attributes of nested models.

company_name = signup[:company][:name]
# File lib/model_orchestration/base.rb, line 159
def [](key)
  send key
end
[]=(key, value) click to toggle source

Set a nested model by name (symbol).

class Signup
  include ModelOrchestration::Base

  nested_model :company
  nested_model :employee

  nested_model_dependency from: :employee, to: :company
end

signup  = Signup.new
signup[:company] = Company.new
# File lib/model_orchestration/base.rb, line 177
def []=(key, value)
  send "#{key}=", value
end
invalid?(context = nil) click to toggle source

See: api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-invalid-3F

# File lib/model_orchestration/base.rb, line 217
def invalid?(context = nil)
  !valid?(context)
end
method_missing(message, *args, &block) click to toggle source

Implements attribute accessor methods for nested models.

Calls superclass method
# File lib/model_orchestration/base.rb, line 183
def method_missing(message, *args, &block)
  if @nested_model_instances.include?(message)
    # Get nested model accessor
    @nested_model_instances[message]
  elsif message =~ /^([^=]+)=$/
    # Set nested model accessor
    attr = message.to_s.chop.to_sym
    if @nested_model_instances.include?(attr)
      @nested_model_instances[attr] = args.first
    else
      super
    end
  else
    super
  end
end
valid?(context = nil) click to toggle source

See: api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-valid-3F

# File lib/model_orchestration/base.rb, line 202
def valid?(context = nil)
  valid = true

  @nested_model_instances.each do |key, instance|
    valid = false unless instance.valid?(context)
  end
  
  valid
end
Also aliased as: validate
validate!(context = nil) click to toggle source

See: api.rubyonrails.org/classes/ActiveModel/Validations.html#method-i-validate-21

# File lib/model_orchestration/base.rb, line 223
def validate!(context = nil)
  valid?(context) || raise_validation_error
end

Protected Instance Methods

initialize_nested_model(model_class, hash_or_instance = {}) click to toggle source
# File lib/model_orchestration/base.rb, line 233
def initialize_nested_model(model_class, hash_or_instance = {})
  if hash_or_instance.is_a? Hash
    model_class.new(hash_or_instance)
  elsif hash_or_instance.is_a? model_class
    hash_or_instance
  else
    raise(TypeError, "hash_or_instance must be of type #{model_class.to_s}")
  end
end
raise_validation_error() click to toggle source
# File lib/model_orchestration/base.rb, line 229
def raise_validation_error
  raise(ValidationError.new(self))
end