app/models/concerns/nested_ancestry_common.rb
module NestedAncestryCommon
extend ActiveSupport::Concern
included do
audited :except => [:title]
has_associated_audits
has_ancestry :orphan_strategy => :restrict
before_validation :set_title
after_update :set_other_titles
after_update :update_matchers, :if => proc { |obj| obj.saved_change_to_title? }
# attribute used by *_names and *_name methods. default is :name
attr_name :title
end
# override title getter
def title
self[:title] || get_title
end
def parent_name
parent.title if parent.present?
end
alias_method :to_label, :title
def get_title
return name if ancestry.empty?
ancestors.map { |a| a.name + '/' }.join + name.to_s
end
alias_method :get_label, :get_title
def to_param
Parameterizable.parameterize("#{id}-#{title}")
end
module ClassMethods
attr_reader :nested_attribute_fields
def nested_attribute_for(*fields)
@nested_attribute_fields = fields
@nested_attribute_fields.each do |field|
# Example method
# def inherited_compute_profile_id
# read_attribute(:compute_profile_id) || nested_compute_profile_id
# end
define_method "inherited_#{field}" do
self[field] || nested(field)
end
# Example method - only override method generated by assocation if there is ancestry.
# if ancestry.present?
# def compute_profile
# ComputeProfile.find_by_id(inherited_compute_profile_id)
# end
# end
if (md = field.to_s.match(/(\w+)_id$/))
define_method md[1] do
if ancestry.present?
klass = md[1].classify
klass = "SmartProxy" if ["puppet_proxy", "puppet_ca_proxy"].include?(md[1])
klass = 'Subnet::Ipv4' if md[1] == 'subnet'
klass = 'Subnet::Ipv6' if md[1] == 'subnet6'
klass.classify.constantize.find_by_id(send("inherited_#{field}"))
else
# () is required. Otherwise, get RuntimeError: implicit argument passing of super from method defined by define_method() is not supported. Specify all arguments explicitly.
super()
end
end
end
end
end
end
def nested(attr)
self.class.sort_by_ancestry(ancestors.where.not(attr => nil)).last.try(attr) if ancestry.present?
end
private
def set_title
self.title = get_title if (name_changed? || ancestry_changed? || self[:title].blank?)
end
def set_other_titles
if saved_change_to_name? || saved_change_to_ancestry?
self.class.where.not(ancestry: nil).find_each do |obj|
if obj.path_ids.include?(id)
obj.update(:title => obj.get_title)
end
end
end
end
def obj_type
self.class.to_s.downcase
end
def update_matchers
lookup_values = LookupValue.where(:match => "#{obj_type}=#{title_before_last_save}")
lookup_values.update_all(:match => "#{obj_type}=#{title}")
end
end