require 'cms/error_handling' # # This module can be added to Controllers to provide support for rendering CMS content pages. # module Cms module ContentRenderingSupport def self.included(base) base.send :include, Cms::ErrorHandling base.rescue_from Exception, :with => :handle_server_error_on_page base.rescue_from ActiveRecord::RecordNotFound, :with => :handle_not_found_on_page base.rescue_from Cms::Errors::ContentNotFound, :with => :handle_not_found_on_page base.rescue_from Cms::Errors::DraftNotFound, :with => :handle_draft_not_found base.rescue_from Cms::Errors::AccessDenied, :with => :handle_access_denied_on_page end def show_content_as_page(content) @page = content # page templates expect a @page attribute @content_block = content # render.html.erb's expect a @content_block attribute end def handle_draft_not_found(exception) logger.warn "Draft Content Not Found" render(:layout => 'cms/application', :template => 'cms/content/no_page', :status => :not_found) end def handle_not_found_on_page(exception) logger.warn "Resource not found: Returning the 404 page." handle_error_with_cms_page(Cms::ErrorPages::NOT_FOUND_PATH, exception, :not_found) end def handle_access_denied_on_page(exception) logger.warn "Access denied for user '#{current_user.login}': Returning the 403 page." handle_error_with_cms_page(Cms::ErrorPages::FORBIDDEN_PATH, exception, :forbidden) end def handle_server_error_on_page(exception) logger.error "An Unexpected exception occurred: #{exception.message}\n" logger.error "#{exception.backtrace.join("\n")}\n" handle_error_with_cms_page(Cms::ErrorPages::SERVER_ERROR_PATH, exception, :internal_server_error) end private # This is the method all error handlers delegate to def handle_error_with_cms_page(error_page_path, exception, status, options={}) # If we are in the CMS, we just want to show the exception if perform_caching return handle_server_error(exception, status) if cms_site? else return handle_server_error(exception, status) if current_user.able_to?(:edit_content, :publish_content) end # We must be showing the page outside of the CMS # So we will show the error page if @page = Cms::Page.find_live_by_path(error_page_path) logger.debug "Rendering Error Page: #{@page.inspect}" @mode = "view" @show_page_toolbar = false # copy new instance variables to the template %w[page mode show_page_toolbar].each do |v| @template.instance_variable_set("@#{v}", instance_variable_get("@#{v}")) end # clear out any content already captured # by previous attempts to render the page within this request @template.instance_variables.select { |v| v =~ /@content_for_/ }.each do |v| @template.instance_variable_set("#{v}", nil) end prepare_connectables_for_render # The error pages are ALWAYS html since they are managed by the CMS as normal pages. # So .gif or .jpg requests that throw errors will return html rather than a format warning. render :layout => @page.layout, :template => 'cms/content/show', :status => status, :formats => [:html] else handle_server_error(exception, status) end end # If any of the page's connectables (portlets, etc) are renderable, they may have a render method # which does "controller" stuff, so we need to get that run before rendering the page. def prepare_connectables_for_render @_connectors = @page.current_connectors @_connectables = @page.contents unless (logged_in? && current_user.able_to?(:administrate, :edit_content, :publish_content)) worst_exception = nil @_connectables.each do |c| begin c.prepare_to_render(self) rescue logger.debug "THROWN EXCEPTION by connectable #{c}: #{$!}" case $! when ActiveRecord::RecordNotFound raise when Cms::Errors::AccessDenied worst_exception = $! else c.render_exception = $! end end end raise worst_exception if worst_exception end end end end