module Scrivito # # This module provides CMS controller actions. # Include it in controller you want to make able to deliver +Obj+s. # # @api public # # @see Scrivito::TestRequest#for_scrivito_obj # # @example # class PageCmsController < ApplicationController # include Scrivito::ControllerActions # end # module ControllerActions extend ActiveSupport::Concern included do before_filter :require_authenticated_editor, only: [ :show_widget, :widget_details, :page_details, ] before_filter :load_object hide_action :on_scrivito_widget_error end # # Default action. # Delivers files directly if +Obj+ is binary. # Otherwise the view is rendered. # # @api public # def index deliver_file if @obj.binary? end def show_widget widget = load_widget widget_tag = Scrivito::WidgetTag.new(view_context, widget, nil, params[:template_name], params[:inner_tag]) render text: widget_tag.render, layout: false end def widget_details assert_dialog_layout widget = load_widget template_path = "#{widget.obj_class_name.underscore}/details" @scrivito_default_widget_template = :details render template_path, layout: 'scrivito_dialog', locals: {widget: widget} end def page_details assert_dialog_layout @scrivito_default_widget_template = :details render @obj.details_view_path, layout: 'scrivito_dialog' rescue ActionView::MissingTemplate render 'scrivito/page_details', layout: 'scrivito_dialog' end # How to handle widget errors in +production+. # # When an exception is raised from within a widget, the entire page is not available. # Often, this is the case in production if the developer has forgotten to handle specific # content scenarios such as empty date attributes, missing titles, unmanaged enum values, etc. # but also for simple coding mistakes during development. # # Override this method to prevent the entire page from being unavailable due to widget errors. # # The overridden method allows to: # * catch a widget error and replace it with an HTML placeholder. # * report a widget error to an external service like Honeybadger or Airbrake. # # This method is _not_ called if Rails is in the +development+ or +test+ environment. # In those environments, all widget errors are just raised. # # By default, this method just reraises the given error. # # @param widget [Scrivito::BasicWidget] the flawed widget # @param error [StandardError] the error that occurred # @raise [StandardError] if this method is not overridden, the +error+ passed to it is reraised. # # @example Notify external service about widget error and render an HTML placeholder: # def on_scrivito_widget_error(widget, error) # # Report error to external service (e.g. Honeybadger or Airbrake): # Honeybadger.notify(error) # notify_airbrake(error) # # # Replace corrupted widget output with a placeholder: # message = "Rendering #{widget.description_for_editor} failed with #{error.message}" # return "".html_safe if Rails.env.production? # "

#{message}

".html_safe # end # @api public def on_scrivito_widget_error(widget, error) raise error end module ClassMethods # # This method indicates if this controller should be used automatically when an +Obj+ is # requested via the SDK's standard routes. It returns +true+ by default. # # Override it to return +false+ if you do want your controller to be excluded from +Obj+ # dispatching. # # @api public # @see Obj#controller_name # def use_for_obj_dispatch? true end end private def require_authenticated_editor head(:forbidden) unless editing_context.authenticated_editor? end def editing_context EditingContextMiddleware.from_request(request) end def comparison editing_context.comparison end def load_object CmsEnv.new(request.env).load loaded_obj = request.env[CmsEnv::OBJ_ENV_KEY] raise loaded_obj if loaded_obj.is_a?(StandardError) @obj = loaded_obj end def load_widget widget = widget_from_current_revision || widget_from_base_revision raise ResourceNotFound, "Widget with ID #{params[:widget_id]} not found!" unless widget widget end def widget_from_current_revision @obj.widget_from_pool(params[:widget_id]) end def widget_from_base_revision if comparison.active? # The "diff" mode. @obj.in_revision(editing_context.selected_workspace.base_revision) .widget_from_pool(params[:widget_id]) end end # # Deliver a binary +Obj+ by redirecting to its {BasicObj#binary Obj#binary}'s url. # Will respond with 404 if the +Obj+ has no +blob+. # # @api public # def deliver_file if binary = @obj.binary url = BinaryRouting.new(request, scrivito_engine).resolved_binary_obj_url(@obj, binary) redirect_to CmsRouting.match_protocol(url, request) else render text: 'Empty Blob', status: 404 end end def assert_dialog_layout view_context.lookup_context.find('layouts/scrivito_dialog') rescue ActionView::MissingTemplate raise %{ Missing the Scrivito dialog layout! Scrivito requires a special view layout in order to render the details dialog. Normally the install generator places it in `app/views/layouts/scrivito_dialog.html.erb`. If upgrading Scrivito, please re-run the install generator: `rails g scrivito:install`. } end end end