Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Fetching contributors…

Cannot retrieve contributors at this time

127 lines (108 sloc) 5.284 kb
module Erector
module Rails
def self.assigns_for(widget_class, view, local_assigns, is_partial)
assigns = {}
instance_variables = view.instance_variables_for_widget_assignment
if is_partial || widget_class.ignore_extra_controller_assigns
instance_variables = remove_unneeded_assigns(widget_class, instance_variables)
end
assigns.merge!(instance_variables) unless is_partial && (! widget_class.controller_assigns_propagate_to_partials)
if is_partial
assigns.merge!(filter_local_assigns_for_partial(widget_class, local_assigns || { }))
end
assigns
end
def self.remove_unneeded_assigns(widget_class, assigns)
needs = widget_class.needed_variables
if needs.empty?
assigns
else
assigns.reject { |key, value| ! needs.include?(key) }
end
end
def self.filter_local_assigns_for_partial(widget_class, local_assigns)
widget_class_variable_name = widget_class.name.underscore
widget_class_variable_name = $1 if widget_class_variable_name =~ %r{.*/(.*?)$}
local_assigns.reject do |name, value|
name == :object || name == widget_class_variable_name.to_sym
end
end
def self.render(widget, view, assigns = nil, options = {})
if widget.is_a?(Class)
assigns ||= assigns_for(widget, view, nil, false)
widget = widget.new(assigns)
end
view.send(:_evaluate_assigns_and_ivars)
view.with_output_buffer do
# Set parent to the view and use Rails's output buffer.
widget.to_html(options.merge(:parent => view,
:output => Output.new { view.output_buffer }))
end
end
module WidgetExtensions
module ClassMethods
def ignore_extra_controller_assigns
out = @ignore_extra_controller_assigns
out ||= (superclass.ignore_extra_controller_assigns ? :true : :false) if superclass.respond_to?(:ignore_extra_controller_assigns)
out ||= :true
out == :true
end
# Often, large Rails applications will assign many controller instance variables.
# Sometimes these aren't used by a view: ApplicationController might assign
# variables that are used by many, but not all, views; and various other things
# may accumulate, especially if you've been using templating systems that are
# more forgiving than Erector. If you then migrate to Erector, you're stuck using
# no "needs" declaration at all, because it needs to contain every assigned
# variable, or Erector will raise an exception.
#
# If you set this to true (and it's inherited through to subclasses), however,
# then "needs" declarations on the widget will cause excess controller variables
# to be ignored -- they'll be unavailable to the widget (so 'needs' still means
# something), but they won't cause widget instantiation to fail, either. This
# can let a large Rails project transition to Erector more smoothly.
def ignore_extra_controller_assigns=(new_value)
@ignore_extra_controller_assigns = (new_value ? :true : :false)
end
def controller_assigns_propagate_to_partials
out = @controller_assigns_propagate_to_partials
out ||= (superclass.controller_assigns_propagate_to_partials ? :true : :false) if superclass.respond_to?(:controller_assigns_propagate_to_partials)
out ||= :true
out == :true
end
# In ERb templates, controller instance variables are available to any partial
# that gets rendered by the view, no matter how deeply-nested. This effectively
# makes controller instance variables "globals". In small view hierarchies this
# probably isn't an issue, but in large ones it can make debugging and
# reasoning about the code very difficult.
#
# If you set this to true (and it's inherited through to subclasses), then any
# widget that's getting rendered as a partial will only have access to locals
# explicitly passed to it (render :partial => ..., :locals => ...). (This
# doesn't change the behavior of widgets that are explicitly rendered, as they
# don't have this issue.) This can allow for cleaner encapsulation of partials,
# as they must be passed everything they use and can't rely on controller
# instance variables.
def controller_assigns_propagate_to_partials=(new_value)
@controller_assigns_propagate_to_partials = (new_value ? :true : :false)
end
end
def self.included(base)
base.extend(ClassMethods)
end
# We need to delegate #capture to parent.capture, so that when
# the captured block is executed, both erector and Rails output
# from within the block go to the appropriate buffer.
def capture(&block)
if parent.respond_to?(:capture)
raw(parent.capture(&block).to_s)
else
super
end
end
# This is here to force #parent.capture to return the output
def __in_erb_template;
end
end
Erector::Widget.send :include, WidgetExtensions
end
end
Jump to Line
Something went wrong with that request. Please try again.