diff --git a/lib/fortitude/rails/renderer.rb b/lib/fortitude/rails/renderer.rb index 0de140b..45d9189 100644 --- a/lib/fortitude/rails/renderer.rb +++ b/lib/fortitude/rails/renderer.rb @@ -11,7 +11,7 @@ module Rails class Renderer class << self # TODO: Refactor this and render :widget => ... support into one method somewhere. - def render(widget_class, template_handler, local_assigns, is_partial, &block) + def render(widget_class, template_handler, local_assigns, is_partial, options = {}, &block) if ::Fortitude::Erector.is_erector_widget_class?(widget_class) return ::Erector::Rails.render(widget_class, template_handler, local_assigns, is_partial, &block) end @@ -25,6 +25,11 @@ def render(widget_class, template_handler, local_assigns, is_partial, &block) end widget = widget_class.new(needed_assigns) + + if options[:pathname] + widget.instance_variable_set(:@virtual_path, options[:pathname]) + end + template_handler.with_output_buffer do rendering_context = template_handler.controller.fortitude_rendering_context_for(template_handler, block) diff --git a/lib/fortitude/rails/template_handler.rb b/lib/fortitude/rails/template_handler.rb index dad61e3..f5dc200 100644 --- a/lib/fortitude/rails/template_handler.rb +++ b/lib/fortitude/rails/template_handler.rb @@ -14,8 +14,10 @@ def call(template, &block) is_partial = !! File.basename(template.identifier) =~ /^_/ + pathname = "#{template.identifier =~ %r(views/(.*)) && $1}" + <<-SRC - Fortitude::Rails::Renderer.render(#{widget_class.name}, self, local_assigns, #{is_partial.inspect}) { |*args| yield *args } + Fortitude::Rails::Renderer.render(#{widget_class.name}, self, local_assigns, #{is_partial.inspect}, pathname: "#{pathname}") { |*args| yield *args } SRC end diff --git a/lib/fortitude/widget.rb b/lib/fortitude/widget.rb index 2618043..90a133e 100644 --- a/lib/fortitude/widget.rb +++ b/lib/fortitude/widget.rb @@ -46,6 +46,9 @@ class Widget if defined?(::Rails) require 'fortitude/rails/widget_methods' include Fortitude::Rails::WidgetMethods + + require 'fortitude/widget/caching' + include Fortitude::Widget::Caching else require 'fortitude/widget/non_rails_widget_methods' include Fortitude::Widget::NonRailsWidgetMethods diff --git a/lib/fortitude/widget/caching.rb b/lib/fortitude/widget/caching.rb new file mode 100644 index 0000000..a74c1d8 --- /dev/null +++ b/lib/fortitude/widget/caching.rb @@ -0,0 +1,38 @@ +module Fortitude + class Widget + module Caching + extend ActiveSupport::Concern + include ActionView::Helpers::CacheHelper + + module ClassMethods + # PUBLIC API + def cacheable(opts = {}) + if extra_assigns == :use + extra_assigns :ignore + end + + static_keys = Array(opts.fetch(:key, [])) + options = opts.fetch(:options, {}) + + define_method(:cache_contents) do |&block| + cache calculate_cache_dependencies(assigns, static_keys), options do + block.call + end + end + + around_content :cache_contents + end + end + + private + + def calculate_cache_dependencies(assigns, static_keys) + ( + assigns.to_a.sort_by(&:first).flatten + + static_keys + + [widget_locale] + ) + end + end + end +end diff --git a/spec/rails/cacheable_method_system_spec.rb b/spec/rails/cacheable_method_system_spec.rb new file mode 100644 index 0000000..c26c36f --- /dev/null +++ b/spec/rails/cacheable_method_system_spec.rb @@ -0,0 +1,10 @@ +describe "Fortitude cacheable method behavior in Rails", :type => :rails do + uses_rails_with_template :cacheable_method_system_spec + + it "caches properly" do + expect_match("localization?locale=en", /hello is: hello 1/) + expect_match("localization?locale=en", /hello is: hello 1/) + expect_match("localization?locale=fr", /hello is: bonjour 2/) + expect_match("localization?locale=fr", /hello is: bonjour 2/) + end +end diff --git a/spec/rails/templates/cacheable_method_system_spec/app/controllers/cacheable_method_system_spec_controller.rb b/spec/rails/templates/cacheable_method_system_spec/app/controllers/cacheable_method_system_spec_controller.rb new file mode 100644 index 0000000..f8f35a6 --- /dev/null +++ b/spec/rails/templates/cacheable_method_system_spec/app/controllers/cacheable_method_system_spec_controller.rb @@ -0,0 +1,11 @@ +class CacheableMethodSystemSpecController < ApplicationController + before_filter :set_locale + + def set_locale + I18n.locale = params[:locale] if params[:locale] + end + + def localization + # nothing here + end +end diff --git a/spec/rails/templates/cacheable_method_system_spec/app/views/cacheable_method_system_spec/localization.rb b/spec/rails/templates/cacheable_method_system_spec/app/views/cacheable_method_system_spec/localization.rb new file mode 100644 index 0000000..63a0e84 --- /dev/null +++ b/spec/rails/templates/cacheable_method_system_spec/app/views/cacheable_method_system_spec/localization.rb @@ -0,0 +1,12 @@ +class Views::CacheableMethodSystemSpec::Localization < Fortitude::Widgets::Html5 + cacheable + + def content + text "hello is: #{t('.hello')} #{times_called}" + end + + def times_called + @@times_called ||= 0 + @@times_called += 1 + end +end diff --git a/spec/rails/templates/cacheable_method_system_spec/config/locales/en.yml b/spec/rails/templates/cacheable_method_system_spec/config/locales/en.yml new file mode 100644 index 0000000..e237774 --- /dev/null +++ b/spec/rails/templates/cacheable_method_system_spec/config/locales/en.yml @@ -0,0 +1,4 @@ +en: + cacheable_method_system_spec: + localization: + hello: "hello" diff --git a/spec/rails/templates/cacheable_method_system_spec/config/locales/fr.yml b/spec/rails/templates/cacheable_method_system_spec/config/locales/fr.yml new file mode 100644 index 0000000..b83813a --- /dev/null +++ b/spec/rails/templates/cacheable_method_system_spec/config/locales/fr.yml @@ -0,0 +1,4 @@ +fr: + cacheable_method_system_spec: + localization: + hello: "bonjour"