mirror of
https://github.com/rails/rails.git
synced 2022-11-09 12:12:34 -05:00
Porting ActionController::Caching to ActionMailer::Caching
This commit is contained in:
parent
2c02bc0a47
commit
049b6e670f
11 changed files with 481 additions and 0 deletions
|
@ -44,6 +44,7 @@ module ActionMailer
|
||||||
autoload :MailHelper
|
autoload :MailHelper
|
||||||
autoload :Preview
|
autoload :Preview
|
||||||
autoload :Previews, 'action_mailer/preview'
|
autoload :Previews, 'action_mailer/preview'
|
||||||
|
autoload :Caching
|
||||||
autoload :TestCase
|
autoload :TestCase
|
||||||
autoload :TestHelper
|
autoload :TestHelper
|
||||||
autoload :MessageDelivery
|
autoload :MessageDelivery
|
||||||
|
|
|
@ -420,6 +420,7 @@ module ActionMailer
|
||||||
class Base < AbstractController::Base
|
class Base < AbstractController::Base
|
||||||
include DeliveryMethods
|
include DeliveryMethods
|
||||||
include Previews
|
include Previews
|
||||||
|
include Caching
|
||||||
|
|
||||||
abstract!
|
abstract!
|
||||||
|
|
||||||
|
|
73
actionmailer/lib/action_mailer/caching.rb
Normal file
73
actionmailer/lib/action_mailer/caching.rb
Normal file
|
@ -0,0 +1,73 @@
|
||||||
|
require 'active_support/descendants_tracker'
|
||||||
|
|
||||||
|
module ActionMailer
|
||||||
|
module Caching
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
extend ActiveSupport::Autoload
|
||||||
|
|
||||||
|
eager_autoload do
|
||||||
|
autoload :Fragments
|
||||||
|
end
|
||||||
|
|
||||||
|
module ConfigMethods
|
||||||
|
def cache_store
|
||||||
|
config.cache_store
|
||||||
|
end
|
||||||
|
|
||||||
|
def cache_store=(store)
|
||||||
|
config.cache_store = ActiveSupport::Cache.lookup_store(store)
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
def cache_configured?
|
||||||
|
perform_caching && cache_store
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
include AbstractController::Helpers
|
||||||
|
include ConfigMethods
|
||||||
|
include Fragments
|
||||||
|
|
||||||
|
included do
|
||||||
|
extend ConfigMethods
|
||||||
|
|
||||||
|
config_accessor :default_static_extension
|
||||||
|
self.default_static_extension ||= '.html'
|
||||||
|
|
||||||
|
config_accessor :perform_caching
|
||||||
|
self.perform_caching = true if perform_caching.nil?
|
||||||
|
|
||||||
|
class_attribute :_view_cache_dependencies
|
||||||
|
self._view_cache_dependencies = []
|
||||||
|
helper_method :view_cache_dependencies if respond_to?(:helper_method)
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
def view_cache_dependency(&dependency)
|
||||||
|
self._view_cache_dependencies += [dependency]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def view_cache_dependencies
|
||||||
|
self.class._view_cache_dependencies.map { |dep| instance_exec(&dep) }.compact
|
||||||
|
end
|
||||||
|
|
||||||
|
protected
|
||||||
|
# Convenience accessor.
|
||||||
|
def cache(key, options = {}, &block)
|
||||||
|
if cache_configured?
|
||||||
|
cache_store.fetch(ActiveSupport::Cache.expand_cache_key(key, :controller), options, &block)
|
||||||
|
else
|
||||||
|
yield
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def perform_caching
|
||||||
|
Base.perform_caching
|
||||||
|
end
|
||||||
|
|
||||||
|
def controller_name
|
||||||
|
"ActionMailer"
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
148
actionmailer/lib/action_mailer/caching/fragments.rb
Normal file
148
actionmailer/lib/action_mailer/caching/fragments.rb
Normal file
|
@ -0,0 +1,148 @@
|
||||||
|
module ActionMailer
|
||||||
|
module Caching
|
||||||
|
# Fragment caching is used for caching various blocks within
|
||||||
|
# views without caching the entire action as a whole. This is
|
||||||
|
# useful when certain elements of an action change frequently or
|
||||||
|
# depend on complicated state while other parts rarely change or
|
||||||
|
# can be shared amongst multiple parties. The caching is done using
|
||||||
|
# the +cache+ helper available in the Action View. See
|
||||||
|
# ActionView::Helpers::CacheHelper for more information.
|
||||||
|
#
|
||||||
|
# While it's strongly recommended that you use key-based cache
|
||||||
|
# expiration (see links in CacheHelper for more information),
|
||||||
|
# it is also possible to manually expire caches. For example:
|
||||||
|
#
|
||||||
|
# expire_fragment('name_of_cache')
|
||||||
|
module Fragments
|
||||||
|
extend ActiveSupport::Concern
|
||||||
|
|
||||||
|
included do
|
||||||
|
if respond_to?(:class_attribute)
|
||||||
|
class_attribute :fragment_cache_keys
|
||||||
|
else
|
||||||
|
mattr_writer :fragment_cache_keys
|
||||||
|
end
|
||||||
|
|
||||||
|
self.fragment_cache_keys = []
|
||||||
|
|
||||||
|
helper_method :fragment_cache_key if respond_to?(:helper_method)
|
||||||
|
end
|
||||||
|
|
||||||
|
module ClassMethods
|
||||||
|
# Allows you to specify controller-wide key prefixes for
|
||||||
|
# cache fragments. Pass either a constant +value+, or a block
|
||||||
|
# which computes a value each time a cache key is generated.
|
||||||
|
#
|
||||||
|
# For example, you may want to prefix all fragment cache keys
|
||||||
|
# with a global version identifier, so you can easily
|
||||||
|
# invalidate all caches.
|
||||||
|
#
|
||||||
|
# class ApplicationController
|
||||||
|
# fragment_cache_key "v1"
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# When it's time to invalidate all fragments, simply change
|
||||||
|
# the string constant. Or, progressively roll out the cache
|
||||||
|
# invalidation using a computed value:
|
||||||
|
#
|
||||||
|
# class ApplicationController
|
||||||
|
# fragment_cache_key do
|
||||||
|
# @account.id.odd? ? "v1" : "v2"
|
||||||
|
# end
|
||||||
|
# end
|
||||||
|
def fragment_cache_key(value = nil, &key)
|
||||||
|
self.fragment_cache_keys += [key || ->{ value }]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Given a key (as described in +expire_fragment+), returns
|
||||||
|
# a key suitable for use in reading, writing, or expiring a
|
||||||
|
# cached fragment. All keys begin with <tt>views/</tt>,
|
||||||
|
# followed by any controller-wide key prefix values, ending
|
||||||
|
# with the specified +key+ value. The key is expanded using
|
||||||
|
# ActiveSupport::Cache.expand_cache_key.
|
||||||
|
def fragment_cache_key(key)
|
||||||
|
head = self.class.fragment_cache_keys.map { |k| instance_exec(&k) }
|
||||||
|
tail = key.is_a?(Hash) ? url_for(key).split("://").last : key
|
||||||
|
ActiveSupport::Cache.expand_cache_key([*head, *tail], :views)
|
||||||
|
end
|
||||||
|
|
||||||
|
# Writes +content+ to the location signified by
|
||||||
|
# +key+ (see +expire_fragment+ for acceptable formats).
|
||||||
|
def write_fragment(key, content, options = nil)
|
||||||
|
return content unless cache_configured?
|
||||||
|
|
||||||
|
key = fragment_cache_key(key)
|
||||||
|
instrument_fragment_cache :write_fragment, key do
|
||||||
|
content = content.to_str
|
||||||
|
cache_store.write(key, content, options)
|
||||||
|
end
|
||||||
|
content
|
||||||
|
end
|
||||||
|
|
||||||
|
# Reads a cached fragment from the location signified by +key+
|
||||||
|
# (see +expire_fragment+ for acceptable formats).
|
||||||
|
def read_fragment(key, options = nil)
|
||||||
|
return unless cache_configured?
|
||||||
|
|
||||||
|
key = fragment_cache_key(key)
|
||||||
|
instrument_fragment_cache :read_fragment, key do
|
||||||
|
result = cache_store.read(key, options)
|
||||||
|
result.respond_to?(:html_safe) ? result.html_safe : result
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Check if a cached fragment from the location signified by
|
||||||
|
# +key+ exists (see +expire_fragment+ for acceptable formats).
|
||||||
|
def fragment_exist?(key, options = nil)
|
||||||
|
return unless cache_configured?
|
||||||
|
key = fragment_cache_key(key)
|
||||||
|
|
||||||
|
instrument_fragment_cache :exist_fragment?, key do
|
||||||
|
cache_store.exist?(key, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
# Removes fragments from the cache.
|
||||||
|
#
|
||||||
|
# +key+ can take one of three forms:
|
||||||
|
#
|
||||||
|
# * String - This would normally take the form of a path, like
|
||||||
|
# <tt>pages/45/notes</tt>.
|
||||||
|
# * Hash - Treated as an implicit call to +url_for+, like
|
||||||
|
# <tt>{ controller: 'pages', action: 'notes', id: 45}</tt>
|
||||||
|
# * Regexp - Will remove any fragment that matches, so
|
||||||
|
# <tt>%r{pages/\d*/notes}</tt> might remove all notes. Make sure you
|
||||||
|
# don't use anchors in the regex (<tt>^</tt> or <tt>$</tt>) because
|
||||||
|
# the actual filename matched looks like
|
||||||
|
# <tt>./cache/filename/path.cache</tt>. Note: Regexp expiration is
|
||||||
|
# only supported on caches that can iterate over all keys (unlike
|
||||||
|
# memcached).
|
||||||
|
#
|
||||||
|
# +options+ is passed through to the cache store's +delete+
|
||||||
|
# method (or <tt>delete_matched</tt>, for Regexp keys).
|
||||||
|
def expire_fragment(key, options = nil)
|
||||||
|
return unless cache_configured?
|
||||||
|
key = fragment_cache_key(key) unless key.is_a?(Regexp)
|
||||||
|
|
||||||
|
instrument_fragment_cache :expire_fragment, key do
|
||||||
|
if key.is_a?(Regexp)
|
||||||
|
cache_store.delete_matched(key, options)
|
||||||
|
else
|
||||||
|
cache_store.delete(key, options)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def instrument_fragment_cache(name, key) # :nodoc:
|
||||||
|
payload = {
|
||||||
|
controller: controller_name,
|
||||||
|
action: action_name,
|
||||||
|
key: key
|
||||||
|
}
|
||||||
|
|
||||||
|
ActiveSupport::Notifications.instrument("#{name}.action_controller", payload) { yield }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
|
@ -25,6 +25,7 @@ module ActionMailer
|
||||||
options.javascripts_dir ||= paths["public/javascripts"].first
|
options.javascripts_dir ||= paths["public/javascripts"].first
|
||||||
options.stylesheets_dir ||= paths["public/stylesheets"].first
|
options.stylesheets_dir ||= paths["public/stylesheets"].first
|
||||||
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
options.show_previews = Rails.env.development? if options.show_previews.nil?
|
||||||
|
options.perform_caching ||= true
|
||||||
|
|
||||||
if options.show_previews
|
if options.show_previews
|
||||||
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
|
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
|
||||||
|
|
232
actionmailer/test/caching_test.rb
Normal file
232
actionmailer/test/caching_test.rb
Normal file
|
@ -0,0 +1,232 @@
|
||||||
|
require 'fileutils'
|
||||||
|
require 'abstract_unit'
|
||||||
|
require 'mailers/base_mailer'
|
||||||
|
require 'mailers/caching_mailer'
|
||||||
|
require 'byebug'
|
||||||
|
|
||||||
|
CACHE_DIR = 'test_cache'
|
||||||
|
# Don't change '/../temp/' cavalierly or you might hose something you don't want hosed
|
||||||
|
FILE_STORE_PATH = File.join(File.dirname(__FILE__), '/../temp/', CACHE_DIR)
|
||||||
|
|
||||||
|
class FragmentCachingMailer < ActionMailer::Base
|
||||||
|
abstract!
|
||||||
|
|
||||||
|
include ActionMailer::Caching
|
||||||
|
|
||||||
|
def some_action; end
|
||||||
|
end
|
||||||
|
|
||||||
|
class BaseCachingTest < ActiveSupport::TestCase
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
@store = ActiveSupport::Cache::MemoryStore.new
|
||||||
|
@mailer = FragmentCachingMailer.new
|
||||||
|
@mailer.perform_caching = true
|
||||||
|
@mailer.cache_store = @store
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_cache_key
|
||||||
|
assert_equal 'views/what a key', @mailer.fragment_cache_key('what a key')
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FragmentCachingTest < BaseCachingTest
|
||||||
|
def test_read_fragment_with_caching_enabled
|
||||||
|
@store.write('views/name', 'value')
|
||||||
|
assert_equal 'value', @mailer.read_fragment('name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_read_fragment_with_caching_disabled
|
||||||
|
@mailer.perform_caching = false
|
||||||
|
@store.write('views/name', 'value')
|
||||||
|
assert_nil @mailer.read_fragment('name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_exist_with_caching_enabled
|
||||||
|
@store.write('views/name', 'value')
|
||||||
|
assert @mailer.fragment_exist?('name')
|
||||||
|
assert !@mailer.fragment_exist?('other_name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_exist_with_caching_disabled
|
||||||
|
@mailer.perform_caching = false
|
||||||
|
@store.write('views/name', 'value')
|
||||||
|
assert !@mailer.fragment_exist?('name')
|
||||||
|
assert !@mailer.fragment_exist?('other_name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_write_fragment_with_caching_enabled
|
||||||
|
assert_nil @store.read('views/name')
|
||||||
|
assert_equal 'value', @mailer.write_fragment('name', 'value')
|
||||||
|
assert_equal 'value', @store.read('views/name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_write_fragment_with_caching_disabled
|
||||||
|
assert_nil @store.read('views/name')
|
||||||
|
@mailer.perform_caching = false
|
||||||
|
assert_equal 'value', @mailer.write_fragment('name', 'value')
|
||||||
|
assert_nil @store.read('views/name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expire_fragment_with_simple_key
|
||||||
|
@store.write('views/name', 'value')
|
||||||
|
@mailer.expire_fragment 'name'
|
||||||
|
assert_nil @store.read('views/name')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_expire_fragment_with_regexp
|
||||||
|
@store.write('views/name', 'value')
|
||||||
|
@store.write('views/another_name', 'another_value')
|
||||||
|
@store.write('views/primalgrasp', 'will not expire ;-)')
|
||||||
|
|
||||||
|
@mailer.expire_fragment(/name/)
|
||||||
|
|
||||||
|
assert_nil @store.read('views/name')
|
||||||
|
assert_nil @store.read('views/another_name')
|
||||||
|
assert_equal 'will not expire ;-)', @store.read('views/primalgrasp')
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_for
|
||||||
|
@store.write('views/expensive', 'fragment content')
|
||||||
|
fragment_computed = false
|
||||||
|
|
||||||
|
view_context = @mailer.view_context
|
||||||
|
|
||||||
|
buffer = 'generated till now -> '.html_safe
|
||||||
|
buffer << view_context.send(:fragment_for, 'expensive') { fragment_computed = true }
|
||||||
|
|
||||||
|
assert !fragment_computed
|
||||||
|
assert_equal 'generated till now -> fragment content', buffer
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_html_safety
|
||||||
|
assert_nil @store.read('views/name')
|
||||||
|
content = 'value'.html_safe
|
||||||
|
assert_equal content, @mailer.write_fragment('name', content)
|
||||||
|
|
||||||
|
cached = @store.read('views/name')
|
||||||
|
assert_equal content, cached
|
||||||
|
assert_equal String, cached.class
|
||||||
|
|
||||||
|
html_safe = @mailer.read_fragment('name')
|
||||||
|
assert_equal content, html_safe
|
||||||
|
assert html_safe.html_safe?
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class FunctionalFragmentCachingTest < BaseCachingTest
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
@store = ActiveSupport::Cache::MemoryStore.new
|
||||||
|
@mailer = CachingMailer.new
|
||||||
|
@mailer.perform_caching = true
|
||||||
|
@mailer.cache_store = @store
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_caching
|
||||||
|
email = @mailer.fragment_cache
|
||||||
|
expected_body = "\"Welcome\""
|
||||||
|
|
||||||
|
assert_match expected_body, email.body.encoded
|
||||||
|
assert_match "\"Welcome\"",
|
||||||
|
@store.read("views/caching/#{template_digest("caching_mailer/fragment_cache")}")
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_fragment_caching_in_partials
|
||||||
|
email = @mailer.fragment_cache_in_partials
|
||||||
|
assert_match(/Old fragment caching in a partial/, email.body.encoded)
|
||||||
|
|
||||||
|
assert_match("Old fragment caching in a partial",
|
||||||
|
@store.read("views/caching/#{template_digest("caching_mailer/_partial")}"))
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_skip_fragment_cache_digesting
|
||||||
|
email = @mailer.skip_fragment_cache_digesting
|
||||||
|
expected_body = "No Digest"
|
||||||
|
|
||||||
|
assert_match expected_body, email.body.encoded
|
||||||
|
assert_match expected_body, @store.read("views/no_digest")
|
||||||
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def template_digest(name)
|
||||||
|
ActionView::Digestor.digest(name: name, finder: @mailer.lookup_context)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class CacheHelperOutputBufferTest < BaseCachingTest
|
||||||
|
|
||||||
|
class MockController
|
||||||
|
def read_fragment(name, options)
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
|
||||||
|
def write_fragment(name, fragment, options)
|
||||||
|
fragment
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def setup
|
||||||
|
super
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_output_buffer
|
||||||
|
output_buffer = ActionView::OutputBuffer.new
|
||||||
|
controller = MockController.new
|
||||||
|
cache_helper = Class.new do
|
||||||
|
def self.controller; end;
|
||||||
|
def self.output_buffer; end;
|
||||||
|
def self.output_buffer=; end;
|
||||||
|
end
|
||||||
|
cache_helper.extend(ActionView::Helpers::CacheHelper)
|
||||||
|
|
||||||
|
cache_helper.stub :controller, controller do
|
||||||
|
cache_helper.stub :output_buffer, output_buffer do
|
||||||
|
assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do
|
||||||
|
assert_nothing_raised do
|
||||||
|
cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_safe_buffer
|
||||||
|
output_buffer = ActiveSupport::SafeBuffer.new
|
||||||
|
controller = MockController.new
|
||||||
|
cache_helper = Class.new do
|
||||||
|
def self.controller; end;
|
||||||
|
def self.output_buffer; end;
|
||||||
|
def self.output_buffer=; end;
|
||||||
|
end
|
||||||
|
cache_helper.extend(ActionView::Helpers::CacheHelper)
|
||||||
|
|
||||||
|
cache_helper.stub :controller, controller do
|
||||||
|
cache_helper.stub :output_buffer, output_buffer do
|
||||||
|
assert_called_with cache_helper, :output_buffer=, [output_buffer.class.new(output_buffer)] do
|
||||||
|
assert_nothing_raised do
|
||||||
|
cache_helper.send :fragment_for, 'Test fragment name', 'Test fragment', &Proc.new{ nil }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
class ViewCacheDependencyTest < BaseCachingTest
|
||||||
|
class NoDependenciesMailer < ActionMailer::Base
|
||||||
|
end
|
||||||
|
class HasDependenciesMailer < ActionMailer::Base
|
||||||
|
view_cache_dependency { "trombone" }
|
||||||
|
view_cache_dependency { "flute" }
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_view_cache_dependencies_are_empty_by_default
|
||||||
|
assert NoDependenciesMailer.new.view_cache_dependencies.empty?
|
||||||
|
end
|
||||||
|
|
||||||
|
def test_view_cache_dependencies_are_listed_in_declaration_order
|
||||||
|
assert_equal %w(trombone flute), HasDependenciesMailer.new.view_cache_dependencies
|
||||||
|
end
|
||||||
|
end
|
3
actionmailer/test/fixtures/caching_mailer/_partial.html.erb
vendored
Normal file
3
actionmailer/test/fixtures/caching_mailer/_partial.html.erb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<% cache :caching do %>
|
||||||
|
Old fragment caching in a partial
|
||||||
|
<% end %>
|
3
actionmailer/test/fixtures/caching_mailer/fragment_cache.html.erb
vendored
Normal file
3
actionmailer/test/fixtures/caching_mailer/fragment_cache.html.erb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<% cache :caching do %>
|
||||||
|
"Welcome"
|
||||||
|
<% end %>
|
1
actionmailer/test/fixtures/caching_mailer/fragment_cache_in_partials.html.erb
vendored
Normal file
1
actionmailer/test/fixtures/caching_mailer/fragment_cache_in_partials.html.erb
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
<%= render "partial" %>
|
3
actionmailer/test/fixtures/caching_mailer/skip_fragment_cache_digesting.html.erb
vendored
Normal file
3
actionmailer/test/fixtures/caching_mailer/skip_fragment_cache_digesting.html.erb
vendored
Normal file
|
@ -0,0 +1,3 @@
|
||||||
|
<%= cache :no_digest, skip_digest: true do %>
|
||||||
|
No Digest
|
||||||
|
<% end %>
|
15
actionmailer/test/mailers/caching_mailer.rb
Normal file
15
actionmailer/test/mailers/caching_mailer.rb
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
class CachingMailer < ActionMailer::Base
|
||||||
|
self.mailer_name = "caching_mailer"
|
||||||
|
|
||||||
|
def fragment_cache
|
||||||
|
mail(subject: "welcome", template_name: "fragment_cache")
|
||||||
|
end
|
||||||
|
|
||||||
|
def fragment_cache_in_partials
|
||||||
|
mail(subject: "welcome", template_name: "fragment_cache_in_partials")
|
||||||
|
end
|
||||||
|
|
||||||
|
def skip_fragment_cache_digesting
|
||||||
|
mail(subject: "welcome", template_name: "skip_fragment_cache_digesting")
|
||||||
|
end
|
||||||
|
end
|
Loading…
Reference in a new issue