cells 3.3.10 → 3.4.0.beta1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. data/CHANGES +0 -8
  2. data/Gemfile +4 -1
  3. data/README.rdoc +91 -107
  4. data/Rakefile +0 -4
  5. data/lib/cell.rb +5 -6
  6. data/lib/{cells/cell → cell}/active_helper.rb +1 -1
  7. data/lib/cell/base.rb +134 -0
  8. data/lib/cell/base_methods.rb +100 -0
  9. data/lib/cell/caching.rb +153 -0
  10. data/lib/cell/rails.rb +239 -0
  11. data/lib/cells.rb +25 -3
  12. data/lib/cells/assertions_helper.rb +1 -1
  13. data/lib/cells/helpers/capture_helper.rb +3 -3
  14. data/lib/cells/rails.rb +65 -4
  15. data/lib/cells/version.rb +3 -1
  16. data/rails_generators/cell/cell_generator.rb +47 -35
  17. data/rails_generators/cell/templates/cell.rb +1 -1
  18. data/rails_generators/cells_install/cells_install_generator.rb +5 -3
  19. data/rails_generators/erb/cell_generator.rb +20 -0
  20. data/rails_generators/{cell → erb}/templates/view.html.erb +0 -0
  21. data/test/active_helper_test.rb +1 -0
  22. data/test/app/cells/bad_guitarist_cell.rb +2 -0
  23. data/test/app/cells/bassist_cell.rb +1 -1
  24. data/test/app/controllers/musician_controller.rb +16 -0
  25. data/test/assertions_helper_test.rb +8 -18
  26. data/test/base_methods_test.rb +40 -0
  27. data/test/cell_generator_test.rb +33 -21
  28. data/test/helper_test.rb +31 -123
  29. data/test/rails/caching_test.rb +215 -0
  30. data/test/rails/capture_test.rb +52 -0
  31. data/test/rails/cells_test.rb +88 -0
  32. data/test/rails/integration_test.rb +37 -0
  33. data/test/rails/render_test.rb +140 -0
  34. data/test/rails/router_test.rb +74 -0
  35. data/test/rails/view_test.rb +24 -0
  36. data/test/test_helper.rb +30 -29
  37. metadata +68 -133
  38. data/.gitignore +0 -3
  39. data/about.yml +0 -7
  40. data/cells.gemspec +0 -26
  41. data/lib/cells/cell.rb +0 -16
  42. data/lib/cells/cell/base.rb +0 -470
  43. data/lib/cells/cell/caching.rb +0 -163
  44. data/lib/cells/cell/test_case.rb +0 -158
  45. data/lib/cells/cell/view.rb +0 -55
  46. data/lib/cells/rails/action_controller.rb +0 -37
  47. data/lib/cells/rails/action_view.rb +0 -37
  48. data/rails/init.rb +0 -44
  49. data/rails_generators/cells_install/templates/tasks.rake +0 -6
  50. data/test/app/cells/a/another_state.html.erb +0 -1
  51. data/test/app/cells/a/existing_view.html.erb +0 -1
  52. data/test/app/cells/a/inherited_view.html.erb +0 -1
  53. data/test/app/cells/a/inherited_view.js.erb +0 -1
  54. data/test/app/cells/a/view_with_locals.html.erb +0 -1
  55. data/test/app/cells/a/view_with_render_call.html.erb +0 -1
  56. data/test/app/cells/b/existing_view.html.erb +0 -1
  57. data/test/app/cells/b/existing_view.js.erb +0 -1
  58. data/test/app/cells/b/layouts/metal.html.erb +0 -1
  59. data/test/app/cells/b/view_with_render_call.html.erb +0 -1
  60. data/test/app/cells/bassist/jam.html.erb +0 -3
  61. data/test/app/cells/bassist/play.html.erb +0 -1
  62. data/test/app/cells/cells_test_one/renamed_instance_view.html.erb +0 -1
  63. data/test/app/cells/cells_test_one/super_state.html.erb +0 -1
  64. data/test/app/cells/cells_test_one_cell.rb +0 -20
  65. data/test/app/cells/cells_test_two_cell.rb +0 -4
  66. data/test/app/cells/helper_using/state_using_application_helper.html.erb +0 -3
  67. data/test/app/cells/helper_using/state_with_automatic_helper_invocation.html.erb +0 -3
  68. data/test/app/cells/helper_using/state_with_helper_invocation.html.erb +0 -3
  69. data/test/app/cells/helper_using/state_with_helper_method_invocation.html.erb +0 -3
  70. data/test/app/cells/layouts/metal.html.erb +0 -1
  71. data/test/app/cells/my_child/hello.html.erb +0 -1
  72. data/test/app/cells/my_mother/bye.html.erb +0 -1
  73. data/test/app/cells/my_mother/hello.html.erb +0 -1
  74. data/test/app/cells/my_test/_broken_partial.html.erb +0 -1
  75. data/test/app/cells/my_test/_partial.html.erb +0 -1
  76. data/test/app/cells/my_test/state_with_instance_var.html.erb +0 -1
  77. data/test/app/cells/my_test/state_with_link_to.html.erb +0 -3
  78. data/test/app/cells/my_test/state_with_not_included_helper_method.html.erb +0 -8
  79. data/test/app/cells/my_test/view_containing_broken_partial.html.erb +0 -3
  80. data/test/app/cells/my_test/view_containing_nonexistant_partial.html.erb +0 -3
  81. data/test/app/cells/my_test/view_containing_partial.html.erb +0 -3
  82. data/test/app/cells/my_test/view_containing_partial_without_cell_name.html.erb +0 -3
  83. data/test/app/cells/my_test/view_in_local_test_views_dir.html.erb +0 -1
  84. data/test/app/cells/my_test/view_with_explicit_english_translation.en.html.erb +0 -1
  85. data/test/app/cells/my_test/view_with_explicit_english_translation.html.erb +0 -1
  86. data/test/app/cells/my_test/view_with_instance_var.html.erb +0 -4
  87. data/test/app/cells/really_module/nested/happy_state.html.erb +0 -1
  88. data/test/app/cells/really_module/nested_cell.rb +0 -11
  89. data/test/app/cells/simple/two_templates_state.html.mytpl +0 -1
  90. data/test/app/cells/simple_cell.rb +0 -7
  91. data/test/app/cells/test/beep.html.erb +0 -1
  92. data/test/app/cells/test/state_invoking_capture.html.erb +0 -7
  93. data/test/app/cells/test/state_invoking_content_for.html.erb +0 -7
  94. data/test/app/cells/test/state_invoking_content_for_twice.html.erb +0 -9
  95. data/test/app/cells/test/state_with_not_included_helper_method.html.erb +0 -8
  96. data/test/app/cells/two_helpers_including/state_using_another_helper.html.erb +0 -3
  97. data/test/bugs_test.rb +0 -23
  98. data/test/caching_test.rb +0 -270
  99. data/test/capture_helper_test.rb +0 -59
  100. data/test/cells_test.rb +0 -352
  101. data/test/rails_test.rb +0 -35
  102. data/test/render_test.rb +0 -305
  103. data/test/test_case_test.rb +0 -106
@@ -0,0 +1,153 @@
1
+ # encoding: utf-8
2
+
3
+ # To improve performance rendered state views can be cached using Rails' caching
4
+ # mechanism.
5
+ # If this it configured (e.g. using our fast friend memcached) all you have to do is to
6
+ # tell Cells which state to cache. You can further attach a proc to expire the
7
+ # cached view.
8
+ #
9
+ # As always I stole a lot of code, this time from Lance Ivy <cainlevy@gmail.com> and
10
+ # his fine components plugin at http://github.com/cainlevy/components.
11
+
12
+ module Cell
13
+ module Caching
14
+
15
+ def self.included(base) #:nodoc:
16
+ base.class_eval do
17
+ extend ClassMethods
18
+
19
+ alias_method_chain :render_state, :caching
20
+ end
21
+ end
22
+
23
+ module ClassMethods
24
+ # Activate caching for the state <tt>state</tt>. If no other options are passed
25
+ # the view will be cached forever.
26
+ #
27
+ # You may pass a Proc or a Symbol as cache expiration <tt>version_proc</tt>.
28
+ # This method is called every time the state is rendered, and is expected to return a
29
+ # Hash containing the cache key ingredients.
30
+ #
31
+ # Additional options will be passed directly to the cache store when caching the state.
32
+ # Useful for simply setting a TTL for a cached state.
33
+ # Note that you may omit the <tt>version_proc</tt>.
34
+ #
35
+ #
36
+ # Example:
37
+ # class CachingCell < ::Cell::Base
38
+ # cache :versioned_cached_state, Proc.new{ {:version => 0} }
39
+ # would result in the complete cache key
40
+ # cells/CachingCell/versioned_cached_state/version=0
41
+ #
42
+ # If you provide a symbol, you can access the cell instance directly in the versioning
43
+ # method:
44
+ #
45
+ # class CachingCell < ::Cell::Base
46
+ # cache :cached_state, :my_cache_version
47
+ #
48
+ # def my_cache_version
49
+ # { :user => current_user.id,
50
+ # :item_id => params[:item] }
51
+ # }
52
+ # end
53
+ # results in a very specific cache key, for customized caching:
54
+ # cells/CachingCell/cached_state/user=18/item_id=1
55
+ #
56
+ # You may also set a TTL only, e.g. when using the memcached store:
57
+ #
58
+ # cache :cached_state, :expires_in => 3.minutes
59
+ #
60
+ # Or use both, having a versioning proc <em>and</em> a TTL expiring the state as a fallback
61
+ # after a certain amount of time.
62
+ #
63
+ # cache :cached_state, Proc.new { {:version => 0} }, :expires_in => 10.minutes
64
+ #--
65
+ ### TODO: implement for string, nil.
66
+ ### DISCUSS: introduce return method #sweep ? so the Proc can explicitly
67
+ ### delegate re-rendering to the outside.
68
+ #--
69
+ def cache(state, version_proc=nil, cache_opts={})
70
+ if version_proc.is_a?(Hash)
71
+ cache_opts = version_proc
72
+ version_proc = nil
73
+ end
74
+
75
+ version_procs[state] = version_proc
76
+ cache_options[state] = cache_opts
77
+ end
78
+
79
+ def version_procs
80
+ @version_procs ||= {}
81
+ end
82
+
83
+ def cache_options
84
+ @cache_options ||= {}
85
+ end
86
+
87
+ def cache_store #:nodoc:
88
+ ::ActionController::Base.cache_store
89
+ end
90
+
91
+ def cache_key_for(cell_class, state, args = {}) #:nodoc:
92
+ key_pieces = [cell_class, state]
93
+
94
+ args.collect{|a,b| [a.to_s, b]}.sort.each{ |k,v| key_pieces << "#{k}=#{v}" }
95
+ key = key_pieces.join('/')
96
+
97
+ ::ActiveSupport::Cache.expand_cache_key(key, :cells)
98
+ end
99
+
100
+ def expire_cache_key(key, opts=nil)
101
+ cache_store.delete(key, opts)
102
+ end
103
+
104
+ def cache_configured?
105
+ ::ActionController::Base.cache_configured?
106
+ end
107
+ end
108
+
109
+ def render_state_with_caching(state, request=ActionDispatch::Request.new({}))
110
+ return render_state_without_caching(state, request) unless state_cached?(state)
111
+
112
+ key = cache_key(state, call_version_proc_for_state(state))
113
+ ### DISCUSS: see sweep discussion at #cache.
114
+
115
+ # cache hit:
116
+ if content = read_fragment(key)
117
+ return content
118
+ end
119
+ # re-render:
120
+ return write_fragment(key, render_state_without_caching(state, request), self.class.cache_options[state])
121
+ end
122
+
123
+ def read_fragment(key, cache_options = nil) #:nodoc:
124
+ returning self.class.cache_store.read(key, cache_options) do |content|
125
+ log "Cell Cache hit: #{key}" unless content.blank?
126
+ end
127
+ end
128
+
129
+ def write_fragment(key, content, cache_opts = nil) #:nodoc:
130
+ log "Cell Cache miss: #{key}"
131
+ self.class.cache_store.write(key, content, cache_opts)
132
+ content
133
+ end
134
+
135
+ # Call the versioning Proc for the respective state.
136
+ def call_version_proc_for_state(state)
137
+ version_proc = self.class.version_procs[state]
138
+
139
+ return {} unless version_proc # call to #cache was without any args.
140
+
141
+ return version_proc.call(self) if version_proc.kind_of?(Proc)
142
+ send(version_proc)
143
+ end
144
+
145
+ def cache_key(state, args = {}) #:nodoc:
146
+ self.class.cache_key_for(self.cell_name, state, args)
147
+ end
148
+
149
+ def state_cached?(state)
150
+ self.class.version_procs.has_key?(state)
151
+ end
152
+ end
153
+ end
@@ -0,0 +1,239 @@
1
+ require 'abstract_controller'
2
+ require 'action_controller'
3
+
4
+ module Cell
5
+ class Rails < ActionController::Metal
6
+ include BaseMethods
7
+ include AbstractController
8
+ include Rendering, Layouts, Helpers, Callbacks, Translation
9
+ include ActionController::RequestForgeryProtection
10
+ #include AbstractController::Logger
11
+
12
+
13
+ #include Cell::ActiveHelper
14
+ cattr_accessor :url_helpers ### TODO: discuss if we really need that or can handle that in cells.rb already.
15
+
16
+ abstract!
17
+
18
+ ### DISCUSS: should we pass the parent_controller here?
19
+ def initialize(parent_controller=nil, options={}) ### FIXME: move to BaseMethods.
20
+ @parent_controller = parent_controller
21
+ @opts = @options = options
22
+ end
23
+ attr_reader :parent_controller
24
+
25
+
26
+ def log(*args); end
27
+
28
+ class View < ActionView::Base
29
+ def render(options = {}, locals = {}, &block)
30
+ if options[:state] or options[:view]
31
+ return @_controller.render(options, &block)
32
+ end
33
+
34
+ super
35
+ end
36
+ end
37
+
38
+ def self.view_context_class
39
+ controller = self
40
+ # Unfortunately, there is currently an abstraction leak between AC::Base
41
+ # and AV::Base which requires having the URL helpers in both AC and AV.
42
+ # To do this safely at runtime for tests, we need to bump up the helper serial
43
+ # to that the old AV subclass isn't cached.
44
+ #
45
+ # TODO: Make this unnecessary
46
+ #if @controller
47
+ # @controller.singleton_class.send(:include, _routes.url_helpers)
48
+ # @controller.view_context_class = Class.new(@controller.view_context_class) do
49
+ # include _routes.url_helpers
50
+
51
+ View.class_eval do
52
+
53
+ include controller._helpers
54
+
55
+ include Cell::Base.url_helpers if Cell::Rails.respond_to?(:url_helpers) and Cell::Rails.url_helpers
56
+ end
57
+
58
+
59
+ @view_context_class ||= View
60
+ ### DISCUSS: copy behaviour from abstract_controller/rendering-line 49? (helpers)
61
+ end
62
+
63
+ def self.controller_path
64
+ @controller_path ||= name.sub(/Cell$/, '').underscore unless anonymous?
65
+ end
66
+
67
+ def process(*) # defined in AC::Metal.
68
+ self.response_body = super ### TODO: discuss with yehuda.
69
+ end
70
+
71
+ #attr_internal :request
72
+ delegate :request, :to => :parent_controller
73
+ delegate :config, :to => :parent_controller # DISCUSS: what if a cell has its own config (eg for assets, cells/bassist/images)?
74
+ # DISCUSS: let @controller point to @parent_controller in views, and @cell is the actual real controller?
75
+
76
+
77
+ def render_state(state, request=ActionDispatch::Request.new({})) ### FIXME: where to set Request if none given? leave blank?
78
+ rack_response = dispatch(state, parent_controller.request)
79
+
80
+ return rack_response[2].last if rack_response[2].kind_of?(Array) ### FIXME: HACK for testing, wtf is going on here?
81
+ rack_response[2] ### TODO: discuss with yehuda.
82
+ # rack_response in test mode: [nil, nil, ["Doo"]]
83
+ # rack_response in dev mode: [nil, nil, "<div>..."]
84
+ end
85
+ include Cell::Caching
86
+
87
+
88
+
89
+
90
+ class << self
91
+ def state2view_cache
92
+ @state2view_cache ||= {}
93
+ end
94
+ end
95
+
96
+
97
+ # Renders the view for the current state and returns the markup for the component.
98
+ # Usually called and returned at the end of a state method.
99
+ #
100
+ # ==== Options
101
+ # * <tt>:view</tt> - Specifies the name of the view file to render. Defaults to the current state name.
102
+ # * <tt>:template_format</tt> - Allows using a format different to <tt>:html</tt>.
103
+ # * <tt>:layout</tt> - If set to a valid filename inside your cell's view_paths, the current state view will be rendered inside the layout (as known from controller actions). Layouts should reside in <tt>app/cells/layouts</tt>.
104
+ # * <tt>:locals</tt> - Makes the named parameters available as variables in the view.
105
+ # * <tt>:text</tt> - Just renders plain text.
106
+ # * <tt>:inline</tt> - Renders an inline template as state view. See ActionView::Base#render for details.
107
+ # * <tt>:file</tt> - Specifies the name of the file template to render.
108
+ # * <tt>:nothing</tt> - Will make the component kinda invisible and doesn't invoke the rendering cycle.
109
+ # * <tt>:state</tt> - Instantly invokes another rendering cycle for the passed state and returns.
110
+ # Example:
111
+ # class MyCell < ::Cell::Base
112
+ # def my_first_state
113
+ # # ... do something
114
+ # render
115
+ # end
116
+ #
117
+ # will just render the view <tt>my_first_state.html</tt>.
118
+ #
119
+ # def my_first_state
120
+ # # ... do something
121
+ # render :view => :my_first_state, :layout => 'metal'
122
+ # end
123
+ #
124
+ # will also use the view <tt>my_first_state.html</tt> as template and even put it in the layout
125
+ # <tt>metal</tt> that's located at <tt>$RAILS_ROOT/app/cells/layouts/metal.html.erb</tt>.
126
+ #
127
+ # def say_your_name
128
+ # render :locals => {:name => "Nick"}
129
+ # end
130
+ #
131
+ # will make the variable +name+ available in the view <tt>say_your_name.html</tt>.
132
+ #
133
+ # def say_your_name
134
+ # render :nothing => true
135
+ # end
136
+ #
137
+ # will render an empty string thus keeping your name a secret.
138
+ #
139
+ #
140
+ # ==== Where have all the partials gone?
141
+ # In Cells we abandoned the term 'partial' in favor of plain 'views' - we don't need to distinguish
142
+ # between both terms. A cell view is both, a view and a kind of partial as it represents only a small
143
+ # part of the page.
144
+ # Just use <tt>:view</tt> and enjoy.
145
+ def render(opts={})
146
+ render_view_for(opts, self.action_name)
147
+ end
148
+
149
+
150
+
151
+ # Climbs up the inheritance hierarchy of the Cell, looking for a view
152
+ # for the current <tt>state</tt> in each level.
153
+ # As soon as a view file is found it is returned as an ActionView::Template
154
+ # instance.
155
+ ### DISCUSS: moved to Cell::View#find_template in rainhead's fork:
156
+ def find_family_view_for_state(state)
157
+ missing_template_exception = nil
158
+
159
+ possible_paths_for_state(state).each do |template_path|
160
+ # we need to catch MissingTemplate, since we want to try for all possible family views.
161
+ begin
162
+ template = find_template(template_path)
163
+ return template if template
164
+ rescue ::ActionView::MissingTemplate => missing_template_exception
165
+ end
166
+ end
167
+
168
+ raise missing_template_exception
169
+ end
170
+
171
+ # In production mode, the view for a state/template_format is cached.
172
+ ### DISCUSS: ActionView::Base already caches results for #pick_template, so maybe
173
+ ### we should just cache the family path for a state/format?
174
+ def find_family_view_for_state_with_caching(state)
175
+ return find_family_view_for_state(state) unless self.class.cache_configured?
176
+
177
+ # in production mode:
178
+ key = "#{state}/#{action_view.template_format}"
179
+ state2view = self.class.state2view_cache
180
+ state2view[key] || state2view[key] = find_family_view_for_state(state, action_view)
181
+ end
182
+
183
+
184
+
185
+
186
+
187
+ # Render the view belonging to the given state. Will raise ActionView::MissingTemplate
188
+ # if it can not find one of the requested view template. Note that this behaviour was
189
+ # introduced in cells 2.3 and replaces the former warning message.
190
+ def render_view_for(opts, state)
191
+ return '' if opts[:nothing]
192
+
193
+ ### TODO: dispatch dynamically:
194
+ if opts[:text] ### FIXME: generic option?
195
+ elsif opts[:inline]
196
+ elsif opts[:file]
197
+ elsif opts[:state] ### FIXME: generic option
198
+ opts[:text] = render_state(opts[:state])
199
+ else
200
+ # handle :layout, :template_format, :view
201
+ opts = defaultize_render_options_for(opts, state)
202
+
203
+ # set instance vars, include helpers:
204
+ #prepare_action_view_for(action_view, opts)
205
+
206
+ #template = find_family_view_for_state_with_caching(opts[:view], action_view)
207
+ template = find_family_view_for_state(opts[:view])
208
+ opts[:template] = template
209
+ end
210
+
211
+ opts = sanitize_render_options(opts)
212
+
213
+ render_to_string(opts)
214
+ end
215
+
216
+ # Defaultize the passed options from #render.
217
+ def defaultize_render_options_for(opts, state)
218
+ opts[:template_format] ||= self.class.default_template_format
219
+ opts[:view] ||= state
220
+ opts
221
+ end
222
+
223
+ def prepare_action_view_for(action_view, opts)
224
+ # make helpers available:
225
+ include_helpers_in_class(action_view.class)
226
+
227
+ import_active_helpers_into(action_view) # in Cells::Cell::ActiveHelper.
228
+
229
+ action_view.assigns = assigns_for_view # make instance vars available.
230
+ action_view.template_format = opts[:template_format]
231
+ end
232
+
233
+ # Prepares <tt>opts</tt> to be passed to ActionView::Base#render by removing
234
+ # unknown parameters.
235
+ def sanitize_render_options(opts)
236
+ opts.except!(:view, :state)
237
+ end
238
+ end
239
+ end
@@ -21,9 +21,14 @@ rescue
21
21
  require 'action_view'
22
22
  end
23
23
 
24
- require 'cells/cell'
25
- require 'cells/helpers'
24
+ require 'cell/base_methods'
25
+
26
26
  require 'cell'
27
+ require 'cells/rails' # helper.
28
+ require 'cell/rails'
29
+
30
+ require 'cells/helpers'
31
+
27
32
 
28
33
  module Cells
29
34
  # Any config should be placed here using +mattr_accessor+.
@@ -63,7 +68,24 @@ module Cells
63
68
  end
64
69
  end
65
70
 
71
+ Cell::Base = Cell::Rails
72
+
66
73
  Cell::Base.view_paths = Cells::DEFAULT_VIEW_PATHS if Cell::Base.view_paths.blank?
67
74
 
68
75
  require 'cells/rails'
69
- require 'cells/cell/test_case' if ENV['RAILS_ENV'] == 'test'
76
+
77
+
78
+ require "rails/railtie"
79
+ class Cells::Railtie < Rails::Railtie
80
+ initializer "cells.attach_router" do |app|
81
+ Cell::Rails.class_eval do
82
+ include app.routes.url_helpers
83
+ end
84
+
85
+ Cell::Base.url_helpers = app.routes.url_helpers
86
+ end
87
+
88
+ initializer "cells.add_load_path" do |app|
89
+ #ActiveSupport::Dependencies.load_paths << Rails.root.join(*%w[app cells])
90
+ end
91
+ end
@@ -40,7 +40,7 @@ module Cells
40
40
  # Example:
41
41
  # assert_equal "Banks kill planet!" cell(:news, :topic => :terror).latest_headline
42
42
  def cell(name, opts={}, &block)
43
- cell = Cell::Base.create_cell_for(@controller, name, opts)
43
+ cell = ::Cell::Base.create_cell_for(@controller, name, opts)
44
44
  cell.instance_eval &block if block_given?
45
45
  cell
46
46
  end
@@ -19,7 +19,7 @@ module Cells
19
19
  #
20
20
  # <%= @greeting %>
21
21
  def global_capture(name, &block)
22
- global_view = controller.instance_variable_get(:@template)
22
+ global_view = controller.parent_controller.view_context
23
23
  content = capture(&block)
24
24
  global_view.send(:instance_variable_set, :"@#{name}", content)
25
25
  end
@@ -38,8 +38,8 @@ module Cells
38
38
  #
39
39
  # <%= yield :greetings %>
40
40
  def global_content_for(name, content = nil, &block)
41
- # OMG.
42
- global_view = controller.instance_variable_get(:@template)
41
+ # OMG. that SUCKS.
42
+ global_view = controller.parent_controller.view_context
43
43
  ivar = :"@content_for_#{name}"
44
44
  content = capture(&block) if block_given?
45
45
  old_content = global_view.send(:'instance_variable_get', ivar)