lib/puffer_pages/backends/models/page.rb
# encoding: UTF-8
class PufferPages::Backends::Page < ActiveRecord::Base
include ActiveUUID::UUID
include PufferPages::Backends::Mixins::Renderable
include PufferPages::Backends::Mixins::Importable
include PufferPages::Backends::Mixins::Localable
self.abstract_class = true
self.table_name = :pages
attr_protected :location
def self.inherited base
base.acts_as_nested_set
super
end
scope :published, where(:status => 'published')
def self.statuses
%w(draft hidden published)
end
def self.controller_scope scope
where scope
end
def self.normalize_path path
path.to_s.split('/').delete_if(&:blank?).join('/').presence
end
def self.find_page location
location = normalize_path(location)
PufferPages.single_section_page_path ?
find_by_slug(location) : find_by_location(location)
end
def self.find_view_page location, options = {}
location = normalize_path(location)
depth = location.to_s.count('/').next
formats = options[:formats].presence || [:html]
if location.blank?
roots.first
else
formats.inject(nil) do |page, format|
page ||= begin
loc = if format == :html
where(['? like location', location])
else
where(['? like location', [location, format].join('.')]).where(['not ? like location', [location, format, ''].join('.')])
end
loc.where(:"#{depth_column_name}" => depth).order('lft desc').first
end
end
end
end
def self.export_json
includes(:page_parts).order(:lft).as_json(
include: :page_parts, except: [:lft, :rgt, :depth, :location]
)
end
def self.import_destroy
roots.destroy_all
end
has_many_page_parts_options = {
order: "name = '#{PufferPages.primary_page_part_name}' desc, name",
dependent: :destroy,
class_name: '::PufferPages::PagePart',
validate: true,
inverse_of: :page
}
has_many_page_parts_options.merge!(include: :translations) if PufferPages.localize
has_many :page_parts, has_many_page_parts_options
accepts_nested_attributes_for :page_parts, :allow_destroy => true
belongs_to :layout, :primary_key => :name, :foreign_key => :layout_name, :class_name => 'PufferPages::Layout'
validates_presence_of :name
validates_uniqueness_of :slug,
:scope => (:parent_id unless PufferPages.single_section_page_path), :allow_nil => true
validates_inclusion_of :status, :in => statuses
validates_format_of :slug,
:with => /\A\s*\Z/, :message => :root_slug_format, :if => :root?
validates_format_of :slug,
:with => /\A([^\/]+)\Z/, :message => :slug_format, :unless => :root?
validate do |page|
page.errors.add(:layout_name, :blank) if page.inherited_layout_name.nil?
end
before_validation :defaultize_attributes
def defaultize_attributes
self.status ||= 'draft'
self.slug = slug.presence
self.location = [parent.try(:location), slug].compact.join('/').presence
end
def location
read_attribute(:location) || [parent.try(:location), slug].compact.join('/').presence
end
before_update :update_locations, :if => :location_changed?
def update_locations
self.class.update_all "location = replace(location, '#{location_was}', '#{location}')", ["location like ?", location_was + '%']
end
statuses.each do |status_name|
define_method "#{status_name}?" do status == status_name end
end
def status
ActiveSupport::StringInquirer.new(read_attribute(:status)) if status?
end
def segments
location.to_s.split ?/
end
def to_location
PufferPages.single_section_page_path ? slug : location
end
def format
File.extname(slug)[1..-1].to_s.to_sym.presence || :html
end
def ancestors_page_parts
self_and_ancestors_page_parts.where('pages.id != ?', id)
end
def self_and_ancestors_page_parts
PufferPages::PagePart
.where("#{q_left} <= ? AND #{q_right} >= ?", left, right)
.joins(:page).order('name, pages.lft desc')
end
def inherited_page_parts
@inherited_page_parts ||= self_and_ancestors_page_parts.group_by(&:name).map { |(_, group)| group.first }
end
def inherited_page_part name
inherited_page_parts.detect { |part| part.name == name }
end
def render *args
source, context = normalize_render_options *args
context = merge_context context, additional_render_options
source ||= inherited_layout
contextualize page_translations: page_translations do
if source
if source.respond_to?(:render)
instrument_render! context do
source.render context
end
else
render_template source, context
end
else
instrument_render! context do
inherited_page_parts.map do |part|
result = part.render context
part.main? ? result : "<% content_for :'#{part.name}' do %>#{result}<% end %>"
end.join
end
end
end
end
def locales_translations; locales; end
def locales_translations=(value); self.locales = value; end
def page_translations
self_and_ancestors.each_with_object({}) do |page, result|
result.deep_merge! page.locales.translations
end
end
def additional_render_options
{ registers: { page: self }, drops: { page: self, self: self }, environment: { processed: self } }
end
def inherited_layout_page
@inherited_layout_page ||= layout_name? ? self : parent.try(:inherited_layout_page)
end
def inherited_layout_name
@inherited_layout_name ||= inherited_layout_page.try(:layout_name)
end
def current_layout
@current_layout ||= inherited_layout_page.try(:layout)
end
def inherited_layout
@inherited_layout ||= PufferPages::Layout.find_layout(current_layout.name) if current_layout
end
def layout_for_render
"layouts/#{inherited_layout_name}" unless inherited_layout
end
def content_type
Rack::Mime.mime_type(File.extname(slug.to_s), 'text/html')
end
def to_liquid
@to_liquid ||= ::PufferPages::Liquid::PageDrop.new(self)
end
end