class Page include Mongoid::Document include Mongoid::Timestamps include MongoSearch::Searchable include Slices::Tree include Slices::PageAsJSON include Slices::HasSlices include Slices::HasAttachments::PageInstanceMethods DESCRIPTION_DEPRECATION_WARNING = "Page#description is now meta_description. If you are upgrading, run 'rake slices:migrate:meta_description' to update." LAST_CHANGED_AT_CACHE_KEY = 'page-last-changed' field :name, localize: Slices::Config.i18n? field :role # only relevant for virtual pages field :active, type: Boolean, default: false field :layout, type: String, default: 'default' field :meta_description, localize: Slices::Config.i18n? field :title, localize: Slices::Config.i18n? field :has_content, type: Boolean, default: false belongs_to :author, class_name: 'Admin' has_slices :slices has_and_belongs_to_many :assets text_search_in :introduction, :extended, :name scope :entries, ->{ all } scope :virtual, ->{ where(:role.ne => nil).asc(:name) } validates_presence_of :name before_save :update_has_content before_destroy :destroy_children after_save :update_last_changed_at after_save :cache_virtual_page class NotFound < RuntimeError; end CACHED_VIRTUAL_PAGES = { 'not_found' => '404', 'error' => '500' } def self.role_for_status(status) if CACHED_VIRTUAL_PAGES.has_value?(status) CACHED_VIRTUAL_PAGES.detect { |k, v| v == status }[0] else nil end end def self.available_layouts Layout.all.map do |human_name, machine_name| { human_name: human_name, machine_name: machine_name } end end # Virtual pages are not associated with a specific URL. Instead, they # can be rendered at any path, depending on the circumstances (e.g. # when a page isn't found, or when an error occurs). Consequently they # aren't created with a :parent attribute. def self.make(attributes = {}) attributes = attributes.symbolize_keys parent = parent_from_attributes(attributes) attributes[:path] ||= path_from_attributes(attributes, parent) new(attributes).tap do |page| yield(page) if block_given? page.parent = parent unless attributes.include?(:role) if parent.present? page.position = parent.children.count page.layout = parent.layout if page.entry? end page.save end end def self.find_by_id(id) ActiveSupport::Deprecation::warn 'Page.find_by_id is depreciated, please use Page.find instead.' find(id) rescue Mongoid::Errors::DocumentNotFound nil end def self.find_by_id!(id) ActiveSupport::Deprecation::warn 'Page.find_by_id is depreciated, please use Page.find instead.' find_by_id(id) || (raise NotFound) end def self.find_virtual(role) find_by(role: role) end def update_last_changed_at Rails.cache.write(LAST_CHANGED_AT_CACHE_KEY, Time.now.to_i) end def self.last_changed_at Rails.cache.read(LAST_CHANGED_AT_CACHE_KEY) || 0 end def cacheable_virtual_page? CACHED_VIRTUAL_PAGES.has_key?(role) end def cache_virtual_page if cacheable_virtual_page? && (! Rails.env.test?) fork do script = File.join(Slices.gem_path, 'script', 'request-local-page') rails = File.join(Rails.root, 'script', 'rails') path = "/#{CACHED_VIRTUAL_PAGES[role]}.html" FileUtils.rm_f(File.join(Rails.root, 'public', path)) exec(rails, 'runner', '-e', Rails.env, script, path) end end end def virtual? role.present? end def entry? false end def set_page? kind_of?(SetPage) end def sets slices.select { |slice| slice.kind_of?(SetSlice) } end def set_slice(kind) slice_class = Object.const_get("#{kind.to_s}SetSlice".camelize) slices.detect { |slice| slice.kind_of?(slice_class) } end def template "pages/show" end def update_attributes(attributes) attributes = attributes.symbolize_keys unless home? if attributes.has_key?(:name) || attributes.has_key?(:permalink) new_path = self.class.path_from_attributes(attributes, parent) attributes[:path] = new_path if new_path != path end if attributes.has_key?(:path) && attributes[:path].blank? attributes.delete(:path) end end super if valid? update_path_for_children if attributes.has_key?(:path) end end # Added in merge or page & content def set_keywords super slices.each do |slice| self._keywords += MongoSearch::KeywordsExtractor.extract(slice.search_text) end self._keywords.uniq! end def available_layouts self.class.available_layouts end # End of added def description ActiveSupport::Deprecation::warn DESCRIPTION_DEPRECATION_WARNING meta_description end def description=(value) ActiveSupport::Deprecation::warn DESCRIPTION_DEPRECATION_WARNING self.meta_description = value end def self.parent_from_attributes(attributes) if attributes.has_key?(:parent_path) Page.find_by_path(attributes.delete(:parent_path)) elsif attributes.has_key?(:parent_id) Page.find(attributes.delete(:parent_id)) else attributes.delete(:parent) end end private_class_method :parent_from_attributes def self.page_exists?(path) Page.find_by_path(path) rescue NotFound false end private_class_method :page_exists? private def update_has_content self.has_content = slices.any? true # must be true otherwise save will fail end def destroy_children children.each { |child| child.destroy } end end