app/models/goldencobra/menue.rb
# encoding: utf-8
# == Schema Information
#
# Table name: goldencobra_menues
#
# id :integer not null, primary key
# title :string(255)
# target :string(255)
# css_class :string(255)
# active :boolean default(TRUE)
# created_at :datetime not null
# updated_at :datetime not null
# ancestry :string(255)
# sorter :integer default(0)
# description :text(65535)
# call_to_action_name :string(255)
# description_title :string(255)
# image_id :integer
# ancestry_depth :integer default(0)
# remote :boolean default(FALSE)
#
module Goldencobra
class Menue < ActiveRecord::Base
attr_accessible :title, :target, :css_class, :active, :ancestry, :parent_id,
:sorter, :description, :call_to_action_name, :description_title,
:image_attributes, :image_id, :permissions_attributes, :remote
has_ancestry orphan_strategy: :rootify, cache_depth: true, touch: true
belongs_to :image, class_name: Goldencobra::Upload, foreign_key: "image_id"
has_many :permissions, -> { where subject_class: "Goldencobra::Menue" },
class_name: Goldencobra::Permission, foreign_key: "subject_id"
validates_presence_of :title
validates_format_of :title, with: /\A[\w\d\?\.\'\!\s&üÜöÖäÄß\-\:\,\"]+\z/
accepts_nested_attributes_for :permissions, allow_destroy: true
if ActiveRecord::Base.connection.table_exists?("goldencobra_settings")
if Goldencobra::Setting.for_key("goldencobra.menues.recreate_cache") == "true"
after_save 'Goldencobra::Article.recreate_cache'
end
end
if ActiveRecord::Base.connection.table_exists?("versions")
has_paper_trail
end
scope :active, -> { where(active: true).order(:sorter) }
scope :inactive, -> { where(active: false).order(:sorter) }
scope :visible, -> { where("css_class <> 'hidden'").where("css_class <> 'not_visible'") }
# Vermutlich ein Active Admin Bug:
# url /admin/menues?q[parent_ids_in]=1 wird mit nil an den Scope
# übergeben. daher hier der HotFix
scope :parent_ids_in_eq, -> (menue_id = 1) { subtree_of(menue_id) }
scope :parent_ids_in, -> (menue_id = 1) { subtree_of(menue_id) }
before_save :set_descendants_status
def self.find_by_pathname(name)
if name.include?("/")
where(title: name.split("/").last).select{|a| a.path.map(&:title).join("/") == name}.first
else
find_by_title(name)
end
end
def is_active?(request)
@is_active_result ||= {}
@is_active_result[request.path.squeeze("/").chomp("/").split("?")[0]] ||= request.path.squeeze("/").chomp("/").split("?")[0] == self.target.gsub("\"",'')
end
def has_active_child?(request, subtree_menues)
@has_active_child_result ||= {}
@has_active_child_result[request.path.squeeze("/").split("?")[0]] ||= has_active_descendant?(subtree_menues, request)
end
def has_active_descendant?(subtree_menues,request)
subtree_menues.select{|a| a.ancestry.to_s.starts_with?("#{self.ancestry}/#{self.id}")}.map(&:target).include?(request.path.squeeze("/").split("?")[0])
end
def has_children
self.has_children?
end
def mapped_to_article?
# TODO: Anfrage dauert zu lange bei 2000 Artikeln
# @mapped_to_article_result ||= Goldencobra::Article.select([:url_name, :startpage, :ancestry, :id]).map{|a| a.public_url}.uniq.include?(self.target)
false
end
def article_id
Goldencobra::Article.select([:url_name, :startpage, :ancestry, :id, :url_path]).select{ |a| a.public_url == target }.first.try(:id)
end
# Render Content of Description with liquid Tags
#
# @return [String] self.description liquified
def liquid_description
template = Liquid::Template.parse(self.description)
template.render(Goldencobra::Article::LiquidParser)
end
def navigation_image
return {} unless self.image
{
"alt_text" => self.image.alt_text ? self.image.alt_text : self.image.image_file_name,
"src" => self.image.image(:original)
}
end
# Filtert die übergebenen mthodennamen anhand einer Whiteliste
# und ersetzt exteren methodenbezeichnungen mit internene helpern
#
# description => liquid_description
#
# @param method_names [Array] Liste an Methodennamen als String
#
# @return [Array] Liste an methoden als Symbol, bereinigt von invaliden aufrufen
def self.filtered_methods(method_names=[])
#Alle zugelasssenen methodennamen als Array of Strings
allowed_attribute_methods = Goldencobra::Menue.new.attributes.keys
additional_whitelist_methods = ["liquid_description", "navigation_image", "article_id"]
all_allowed_methodes = allowed_attribute_methods + additional_whitelist_methods
#Filter übergebene methodenliste auf die zugelassenen namen
selected_methods = method_names.select{ |a| all_allowed_methodes.include?(a) }
#Wandle method names um in Symbols
method_names = selected_methods.map{ |a| a.to_sym }
return method_names.sort
end
# Liefert ein Hash der übegenene Anestry Arranged Daten
# @param nodes [Goldencobra::Menue] Ein Eltern-Menüelement
# @param display_methods [:method] Optionale Liste an Mehtoden die auf das Menüelement aufgerufen werden sollen
#
# {
# id: node.id,
# title: node.title,
# target: node.target,
# eg_desciption: node.eg_description
# children: json_tree(sub_nodes).compact
# }
#
# @return [Hash] Hash of Menue Data with optional attributes
def self.json_tree(nodes, display_methods )
nodes.map do |node, sub_nodes|
node.as_json(only: [:id, :title, :target], methods: display_methods).merge({children: json_tree(sub_nodes, display_methods).compact})
end
end
# **************************
# **************************
# Private Methods
# **************************
# **************************
private
def set_descendants_status
if !self.new_record? && self.active_changed? && self.descendants.any?
# Save without callbacks
if Rails::VERSION::MAJOR == 3
self.descendants.map{ |d| d.update_column(:active, self.active) }
elsif Rails::VERSION::MAJOR > 3
self.descendants.map{ |d| d.update_columns(active: self.active) }
end
end
end
# Allow Scopes and Methods to search for in ransack (n.a. metasearch)
# @param auth_object = nil [self] "if auth_object.try(:admin?)"
#
# @return [Array] Array of Symbols representing scopes and class methods
def self.ransackable_scopes(auth_object = nil)
[ :parent_ids_in ]
end
end
end
# has_ancestry Doku
#
# parent Returns the parent of the record, nil for a root node
# parent_id Returns the id of the parent of the record, nil for a root node
# root Returns the root of the tree the record is in, self for a root node
# root_id Returns the id of the root of the tree the record is in
# is_root? Returns true if the record is a root node, false otherwise
# ancestor_ids Returns a list of ancestor ids, starting with the root id and ending with the parent id
# ancestors Scopes the model on ancestors of the record
# path_ids Returns a list the path ids, starting with the root id and ending with the node's own id
# path Scopes model on path records of the record
# children Scopes the model on children of the record
# child_ids Returns a list of child ids
# has_children? Returns true if the record has any children, false otherwise
# is_childless? Returns true is the record has no childen, false otherwise
# siblings Scopes the model on siblings of the record, the record itself is included
# sibling_ids Returns a list of sibling ids
# has_siblings? Returns true if the record's parent has more than one child
# is_only_child? Returns true if the record is the only child of its parent
# descendants Scopes the model on direct and indirect children of the record
# descendant_ids Returns a list of a descendant ids
# subtree Scopes the model on descendants and itself
# subtree_ids Returns a list of all ids in the record's subtree
# depth Return the depth of the node, root nodes are at depth 0