require "fmrest/spyke/model/orm"
module FmRest
module Spyke
module Model
module Attributes
extend ::ActiveSupport::Concern
include Orm
include ::ActiveModel::Dirty
include ::ActiveModel::ForbiddenAttributesProtection
included do
if respond_to? :attribute_method_patterns
attribute_method_patterns.shift
else
attribute_method_matchers.shift
end
class_attribute :mapped_attributes, instance_writer: false, instance_predicate: false,
default: ::ActiveSupport::HashWithIndifferentAccess.new.freeze
class << self; private :mapped_attributes=; end
set_callback :save, :after, :changes_applied_after_save
end
class_methods do
def attributes(*attrs)
if attrs.length == 1 && attrs.first.kind_of?(Hash)
attrs.first.each { |from, to| _fmrest_define_attribute(from, to) }
else
attrs.each { |attr| _fmrest_define_attribute(attr, attr) }
end
end
private
def new_or_return(attributes_or_object, *_)
return super if attributes_or_object.is_a?(::Spyke::Base)
super.tap do |record|
if record.respond_to?(:clear_changes_information)
record.clear_changes_information
else
record.send(:clear_changes_information)
end
end
end
def _fmrest_attribute_methods_container
@fmrest_attribute_methods_container ||= Module.new.tap { |mod| include mod }
end
def _fmrest_define_attribute(from, to)
if existing_method = ((method_defined?(from) || private_method_defined?(from)) && from) ||
((method_defined?("#{from}=") || private_method_defined?("#{from}=")) && "#{from}=")
raise ArgumentError, "You tried to define an attribute named `#{from}' on `#{name}', but this will generate a instance method `#{existing_method}', which is already defined by FmRest::Layout."
end
self.mapped_attributes = mapped_attributes.merge(from => to.to_s).freeze
_fmrest_attribute_methods_container.module_eval do
define_method(from) do
attribute(to)
end
define_method(:"#{from}=") do |value|
send("#{from}_will_change!") unless value == send(from)
set_attribute(to, value)
end
end
define_attribute_method(from)
end
end
def reload(*args)
super.tap { |r| clear_changes_information }
end
def attributes=(new_attributes)
@spyke_attributes ||= ::Spyke::Attributes.new(scope.params)
return unless new_attributes && !new_attributes.empty?
use_setters(sanitize_for_mass_assignment(new_attributes))
end
private
def changed_params
attributes.to_params.slice(*mapped_changed)
end
def mapped_changed
mapped_attributes.values_at(*changed)
end
def inspect_attributes
mapped_attributes.except(primary_key).map do |k, v|
"#{k}: #{attribute(v).inspect}"
end.join(', ')
end
def changes_applied_after_save
changes_applied
portals.each(&:parent_changes_applied)
end
end
end
end
end