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_action :require_authenticated_editor, only: [ :show_widget, :widget_details, :page_details, ] before_action :load_object if LegacySwitch.rails4? hide_action :on_scrivito_widget_error end helper :scrivito 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, render_context: params[:render_mode], inner_tag: params[:inner_tag]) render plain: widget_tag.render, layout: false end def widget_details assert_dialog_layout widget = load_widget @scrivito_widget_render_context = :details render widget.details_view_path, layout: 'scrivito_dialog', locals: {widget: widget} end def page_details assert_dialog_layout @scrivito_widget_render_context = :details render @obj.details_view_path, layout: 'scrivito_dialog' rescue ActionView::MissingTemplate render 'scrivito/page_details', layout: 'scrivito_dialog' end # @!method on_scrivito_widget_error(widget, error) # 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. # # By default, Scrivito handles exceptions raised while rendering a widget by adding a # placeholder text to the HTML indicating that the widget couldn't be rendered. In addition, # the exception is logged alongside with its backtrace. # # Override this method to adapt this behaviour. # # 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. # # @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 # This empty line is necessary for yard to function correctly 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 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 binary_routing = BinaryRouting.new(request, scrivito_engine) redirect_to binary_routing.resolved_binary_url(binary) else render plain: '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