require 'active_support/concern' module Fortitude module Rails module RenderingMethods extend ActiveSupport::Concern included do alias_method_chain :render, :fortitude end def fortitude_rendering_context_for(delegate_object, yield_block) @_fortitude_rendering_contexts ||= { } @_fortitude_rendering_contexts[delegate_object.object_id] ||= create_fortitude_rendering_context( :delegate_object => delegate_object, :yield_block => yield_block) end def create_fortitude_rendering_context(options) ::Fortitude::RenderingContext.new(options) end # This is our support for render :widget. Although, originally, it looked like creating a new subclass # of ActionView::Template was going to be the correct thing to do here, it turns out it isn't: the entire # template system is predicated around the idea that you have a template, which is compiled to output # Ruby source code, and then that gets evaluated to actually generate output. # # Because render :widget => ... takes an already-instantiated widget as input, this simply isn't # possible: you can't reverse-engineer an arbitrary Ruby object into source code, and, without source code, # the whole templating paradigm doesn't make sense. # # So, instead, we simply transform render :widget => ... into a render :text => ... of the # widget's output, and let Rails take it away from there. def render_with_fortitude(*args, &block) if (options = args[0]).kind_of?(Hash) if (widget = options[:widget]) rendering_context = fortitude_rendering_context_for(self, nil) widget.render_to(rendering_context) options = options.dup options[:text] = rendering_context.output_buffer_holder.output_buffer.html_safe options[:layout] = true unless options.has_key?(:layout) new_args = [ options ] + args[1..-1] return render_without_fortitude(*new_args, &block) elsif (widget_block = options[:inline]) && (options[:type] == :fortitude) options.delete(:inline) rendering_context = fortitude_rendering_context_for(self, nil) widget_class = Class.new(Fortitude::Widgets::Html5) widget_class.use_instance_variables_for_assigns(true) widget_class.extra_assigns(:use) widget_class.send(:define_method, :content, &widget_block) assigns = { } instance_variables.each do |ivar_name| value = instance_variable_get(ivar_name) assigns[$1.to_sym] = value if ivar_name =~ /^@(.*)$/ end assigns = assigns.merge(options[:locals] || { }) widget = widget_class.new(assigns) widget.render_to(rendering_context) options = options.dup options[:text] = rendering_context.output_buffer_holder.output_buffer.html_safe options[:layout] = true unless options.has_key?(:layout) new_args = [ options ] + args[1..-1] return render_without_fortitude(*new_args, &block) end end return render_without_fortitude(*args, &block) end end end end