class PublicController < ApplicationController def render_template(name, locals={}, options={}) environment = { site: @current_site.to_drop, request: LiquorRequest.new(request, self), }.merge(locals) if production_domain? pack = @current_site.production_pack else pack = @current_site.development_pack end manager = LiquorTemplateLoader.load_with_caching(pack, :html) if !manager.success? show_errors_with_splash_page(manager, name, manager.errors) return end if !manager.has_template?(name) if name == '404' render file: Rails.root.join('public', '404.html'), status: :not_found, layout: false else render_404 end return end with_layout = options.delete(:layout) with_layout = true if with_layout.nil? if with_layout layout_name = 'layout' end headers["Content-Type"] ||= 'text/html; charset=utf-8' handle_liquor_errors(manager, name) do render :liquor => { :manager => manager, :template => name, :layout => layout_name, :environment => environment, } end end rescue_from ActiveRecord::RecordNotFound, with: :render_404 rescue_from ActionController::RoutingError, with: :render_404 def render_404(error=nil) # UserResourcesController: # 1) Gets invoked when used from the main site, # 2) Needs to render templates, thus subclasses PublicController, # 3) Raises AC::RoutingError even when on the main site. if on_the_main_site? raise error else render_template '404' end end protected def handle_liquor_errors(manager, template_name) if production_domain? errors = Liquor::Runtime.capture_errors do yield end if errors.any? # Type errors are caught here. They are posted to ErrorApp and # appended as console.log() to response body. enqueue_liquor_error(manager, template_name, errors, false) append_errors_to_response_body(manager, template_name, errors) end else yield end # rescue Liquor::HostError => e # In the future, HostErrors should be handled distinctively, as they # signify that _we_ fucked up, as opposed to the template author. # For now, everything is posted into our Airbrake anyway. rescue Liquor::SourceMappedError => e if production_domain? # Type errors will be caught and munged in the code above. If a # Liquor::SourceMappedError falls through, then it's more severe, # cannot be munged and so the app should show 500 instead. enqueue_liquor_error(manager, template_name, [ e ], true) render file: Rails.root.join('public', '500.html'), status: :internal_server_error, layout: false else # If we have arrived here from development mode, then this is # any template error, as type errors are not munged in developer mode. # Show splashscreen to the user. show_errors_with_splash_page(manager, template_name, [ e ]) end end def enqueue_liquor_error(manager, template_name, errors, is_500=true) job = LiquorRuntimeErrorJob.new( @current_site, request.url, template_name, errors, is_500) Delayed::Job.enqueue(job) end def show_errors_with_splash_page(manager, template_name, errors) @manager = manager @errors = errors render 'public/liquor_errors', layout: 'dev' end def append_errors_to_response_body(manager, template_name, errors) log_statements = errors.map do |e| %Q{console.log("Liquor error: " + #{e.message.inspect} + "\\n" + #{manager.decorate(e).join("\\n").inspect});} end.join("\n ") script = <<-SCRIPT SCRIPT response.body = response.body.sub %r{()}, "#{script}\\1" end end