denkGroot/Spina

View on GitHub
app/models/spina/page.rb

Summary

Maintainability
A
0 mins
Test Coverage
module Spina
  class Page < ApplicationRecord
    extend Mobility
    include Partable

    # Stores the old path when generating a new materialized_path
    attr_accessor :old_path

    # Page contains multiple parts called PageParts
    has_many :page_parts, dependent: :destroy, inverse_of: :page
    alias_attribute :parts, :page_parts
    accepts_nested_attributes_for :page_parts, allow_destroy: true

    # Orphaned pages are adopted by parent pages if available, otherwise become root
    has_ancestry orphan_strategy: :adopt

    # Pages can belong to navigations (optional)
    has_many :navigation_items, dependent: :destroy
    has_many :navigations, through: :navigation_items

    # Pages can belong to a resource
    belongs_to :resource, optional: true

    scope :regular_pages, ->  { where(resource: nil) }
    scope :resource_pages, -> { where.not(resource: nil) }
    scope :active, -> { where(active: true) }
    scope :sorted, -> { order(:position) }
    scope :live, -> { active.where(draft: false) }
    scope :in_menu, -> { where(show_in_menu: true) }

    # Save children to update all materialized_paths
    after_save :save_children
    after_save :touch_navigations
    after_save -> { page_parts.each(&:save) }

    # Create a 301 redirect if materialized_path changed
    after_save :rewrite_rule

    before_validation :set_materialized_path
    validates :title, presence: true

    translates :title, fallbacks: true
    translates :description, :materialized_path
    translates :menu_title, :seo_title, default: -> { title }

    def to_s
      name
    end

    def page_id
      id
    end

    def url_title
      title.try(:parameterize)
    end

    def custom_page?
      !deletable
    end

    def save_children
      self.children.each(&:save)
    end

    def live?
      !draft? && active?
    end

    def previous_sibling
      self.siblings.where('position < ?', self.position).sorted.last
    end

    def next_sibling
      self.siblings.where('position > ?', self.position).sorted.first
    end

    def set_materialized_path
      self.old_path = materialized_path
      self.materialized_path = localized_materialized_path
      self.materialized_path = localized_materialized_path + "-#{self.class.i18n.where(materialized_path: materialized_path).count}" if self.class.i18n.where(materialized_path: materialized_path).where.not(id: id).count > 0
      materialized_path
    end

    def cache_key
      super + "_" + Mobility.locale.to_s
    end

    def view_template_config(theme)
      view_template_name = view_template.presence || 'show'
      theme.view_templates.find { |template| template[:name] == view_template_name }
    end

    def view_template_page_parts(theme)
      theme.page_parts.select { |page_part| page_part[:name].in? view_template_config(theme)[:page_parts] }
    end

    private

      def touch_navigations
        navigations.update_all(updated_at: Time.zone.now)
      end

      def rewrite_rule
        RewriteRule.where(old_path: old_path).first_or_create.update_attributes(new_path: materialized_path) if old_path != materialized_path
      end

      def localized_materialized_path
        if I18n.locale == I18n.default_locale
          generate_materialized_path.prepend('/')
        else
          generate_materialized_path.prepend("/#{I18n.locale}/").gsub(/\/\z/, "")
        end
      end

      def generate_materialized_path
        if root?
          name == 'homepage' ? '' : "#{url_title}"
        else
          ancestors.collect(&:url_title).append(url_title).join('/')
        end
      end

  end
end