aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer/lib
diff options
context:
space:
mode:
Diffstat (limited to 'actionmailer/lib')
-rw-r--r--actionmailer/lib/action_mailer.rb4
-rw-r--r--actionmailer/lib/action_mailer/base.rb60
-rw-r--r--actionmailer/lib/action_mailer/preview.rb73
-rw-r--r--actionmailer/lib/action_mailer/railtie.rb10
-rw-r--r--actionmailer/lib/action_mailer/version.rb2
5 files changed, 131 insertions, 18 deletions
diff --git a/actionmailer/lib/action_mailer.rb b/actionmailer/lib/action_mailer.rb
index 5b6960c8fc..83969d4074 100644
--- a/actionmailer/lib/action_mailer.rb
+++ b/actionmailer/lib/action_mailer.rb
@@ -1,5 +1,5 @@
#--
-# Copyright (c) 2004-2013 David Heinemeier Hansson
+# Copyright (c) 2004-2014 David Heinemeier Hansson
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
@@ -41,6 +41,8 @@ module ActionMailer
autoload :Base
autoload :DeliveryMethods
autoload :MailHelper
+ autoload :Preview
+ autoload :Previews, 'action_mailer/preview'
autoload :TestCase
autoload :TestHelper
end
diff --git a/actionmailer/lib/action_mailer/base.rb b/actionmailer/lib/action_mailer/base.rb
index 501fee55aa..275f657f8a 100644
--- a/actionmailer/lib/action_mailer/base.rb
+++ b/actionmailer/lib/action_mailer/base.rb
@@ -50,7 +50,7 @@ module ActionMailer
#
# * <tt>mail</tt> - Allows you to specify email to be sent.
#
- # The hash passed to the mail method allows you to specify any header that a Mail::Message
+ # The hash passed to the mail method allows you to specify any header that a <tt>Mail::Message</tt>
# will accept (any valid Email header including optional fields).
#
# The mail method, if not passed a block, will inspect your views and send all the views with
@@ -229,7 +229,7 @@ module ActionMailer
# An interceptor class must implement the <tt>:delivering_email(message)</tt> method which will be
# called before the email is sent, allowing you to make modifications to the email before it hits
# the delivery agents. Your class should make any needed modifications directly to the passed
- # in Mail::Message instance.
+ # in <tt>Mail::Message</tt> instance.
#
# = Default Hash
#
@@ -308,6 +308,28 @@ module ActionMailer
# Note that unless you have a specific reason to do so, you should prefer using before_action
# rather than after_action in your ActionMailer classes so that headers are parsed properly.
#
+ # = Previewing emails
+ #
+ # You can preview your email templates visually by adding a mailer preview file to the
+ # <tt>ActionMailer::Base.preview_path</tt>. Since most emails do something interesting
+ # with database data, you'll need to write some scenarios to load messages with fake data:
+ #
+ # class NotifierPreview < ActionMailer::Preview
+ # def welcome
+ # Notifier.welcome(User.first)
+ # end
+ # end
+ #
+ # Methods must return a <tt>Mail::Message</tt> object which can be generated by calling the mailer
+ # method without the additional <tt>deliver</tt>. The location of the mailer previews
+ # directory can be configured using the <tt>preview_path</tt> option which has a default
+ # of <tt>test/mailers/previews</tt>:
+ #
+ # config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
+ #
+ # An overview of all previews is accessible at <tt>http://localhost:3000/rails/mailers</tt>
+ # on a running development server instance.
+ #
# = Configuration options
#
# These options are specified on the class level, like
@@ -317,7 +339,7 @@ module ActionMailer
# per the above section.
#
# * <tt>logger</tt> - the logger is used for generating information on the mailing run if available.
- # Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
+ # Can be set to +nil+ for no logging. Compatible with both Ruby's own +Logger+ and Log4r loggers.
#
# * <tt>smtp_settings</tt> - Allows detailed configuration for <tt>:smtp</tt> delivery method:
# * <tt>:address</tt> - Allows you to use a remote mail server. Just change it from its default
@@ -335,8 +357,9 @@ module ActionMailer
# and starts to use it.
# * <tt>:openssl_verify_mode</tt> - When using TLS, you can set how OpenSSL checks the certificate. This is
# really useful if you need to validate a self-signed and/or a wildcard certificate. You can use the name
- # of an OpenSSL verify constant ('none', 'peer', 'client_once', 'fail_if_no_peer_cert') or directly the
- # constant (OpenSSL::SSL::VERIFY_NONE, OpenSSL::SSL::VERIFY_PEER, ...).
+ # of an OpenSSL verify constant (<tt>'none'</tt>, <tt>'peer'</tt>, <tt>'client_once'</tt>,
+ # <tt>'fail_if_no_peer_cert'</tt>) or directly the constant (<tt>OpenSSL::SSL::VERIFY_NONE</tt>,
+ # <tt>OpenSSL::SSL::VERIFY_PEER</tt>, ...).
#
# * <tt>sendmail_settings</tt> - Allows you to override options for the <tt>:sendmail</tt> delivery method.
# * <tt>:location</tt> - The location of the sendmail executable. Defaults to <tt>/usr/sbin/sendmail</tt>.
@@ -351,7 +374,7 @@ module ActionMailer
#
# * <tt>delivery_method</tt> - Defines a delivery method. Possible values are <tt>:smtp</tt> (default),
# <tt>:sendmail</tt>, <tt>:test</tt>, and <tt>:file</tt>. Or you may provide a custom delivery method
- # object e.g. MyOwnDeliveryMethodClass. See the Mail gem documentation on the interface you need to
+ # object e.g. +MyOwnDeliveryMethodClass+. See the Mail gem documentation on the interface you need to
# implement for a custom delivery agent.
#
# * <tt>perform_deliveries</tt> - Determines whether emails are actually sent from Action Mailer when you
@@ -362,6 +385,7 @@ module ActionMailer
# <tt>delivery_method :test</tt>. Most useful for unit and functional testing.
class Base < AbstractController::Base
include DeliveryMethods
+ include Previews
abstract!
@@ -373,6 +397,8 @@ module ActionMailer
include AbstractController::AssetPaths
include AbstractController::Callbacks
+ include ActionView::Layouts
+
PROTECTED_IVARS = AbstractController::Rendering::DEFAULT_PROTECTED_INSTANCE_VARIABLES + [:@_action_has_layout]
def _protected_ivars # :nodoc:
@@ -404,7 +430,7 @@ module ActionMailer
# Register an Observer which will be notified when mail is delivered.
# Either a class or a string can be passed in as the Observer. If a string is passed in
- # it will be +constantize+d.
+ # it will be <tt>constantize</tt>d.
def register_observer(observer)
delivery_observer = (observer.is_a?(String) ? observer.constantize : observer)
Mail.register_observer(delivery_observer)
@@ -462,11 +488,11 @@ module ActionMailer
end
end
- # Wraps an email delivery inside of ActiveSupport::Notifications instrumentation.
+ # Wraps an email delivery inside of <tt>ActiveSupport::Notifications</tt> instrumentation.
#
- # This method is actually called by the Mail::Message object itself
- # through a callback when you call +:deliver+ on the Mail::Message,
- # calling +deliver_mail+ directly and passing a Mail::Message will do
+ # This method is actually called by the <tt>Mail::Message</tt> object itself
+ # through a callback when you call <tt>:deliver</tt> on the <tt>Mail::Message</tt>,
+ # calling +deliver_mail+ directly and passing a <tt>Mail::Message</tt> will do
# nothing except tell the logger you sent the email.
def deliver_mail(mail) #:nodoc:
ActiveSupport::Notifications.instrument("deliver.action_mailer") do |payload|
@@ -542,18 +568,18 @@ module ActionMailer
self.class.mailer_name
end
- # Allows you to pass random and unusual headers to the new Mail::Message
+ # Allows you to pass random and unusual headers to the new <tt>Mail::Message</tt>
# object which will add them to itself.
#
# headers['X-Special-Domain-Specific-Header'] = "SecretValue"
#
# You can also pass a hash into headers of header field names and values,
- # which will then be set on the Mail::Message object:
+ # which will then be set on the <tt>Mail::Message</tt> object:
#
# headers 'X-Special-Domain-Specific-Header' => "SecretValue",
# 'In-Reply-To' => incoming.message_id
#
- # The resulting Mail::Message will have the following in its header:
+ # The resulting <tt>Mail::Message</tt> will have the following in its header:
#
# X-Special-Domain-Specific-Header: SecretValue
def headers(args = nil)
@@ -642,8 +668,8 @@ module ActionMailer
# templates in the view paths using by default the mailer name and the
# method name that it is being called from, it will then create parts for
# each of these templates intelligently, making educated guesses on correct
- # content type and sequence, and return a fully prepared Mail::Message
- # ready to call +:deliver+ on to send.
+ # content type and sequence, and return a fully prepared <tt>Mail::Message</tt>
+ # ready to call <tt>:deliver</tt> on to send.
#
# For example:
#
@@ -689,6 +715,8 @@ module ActionMailer
# end
#
def mail(headers = {}, &block)
+ return @_message if @_mail_was_called && headers.blank? && !block
+
@_mail_was_called = true
m = @_message
diff --git a/actionmailer/lib/action_mailer/preview.rb b/actionmailer/lib/action_mailer/preview.rb
new file mode 100644
index 0000000000..ecceaf8c70
--- /dev/null
+++ b/actionmailer/lib/action_mailer/preview.rb
@@ -0,0 +1,73 @@
+require 'active_support/descendants_tracker'
+
+module ActionMailer
+ module Previews #:nodoc:
+ extend ActiveSupport::Concern
+
+ included do
+ # Set the location of mailer previews through app configuration:
+ #
+ # config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
+ #
+ class_attribute :preview_path, instance_writer: false
+ end
+ end
+
+ class Preview
+ extend ActiveSupport::DescendantsTracker
+
+ class << self
+ # Returns all mailer preview classes
+ def all
+ load_previews if descendants.empty?
+ descendants
+ end
+
+ # Returns the mail object for the given email name
+ def call(email)
+ preview = self.new
+ preview.public_send(email)
+ end
+
+ # Returns all of the available email previews
+ def emails
+ public_instance_methods(false).map(&:to_s).sort
+ end
+
+ # Returns true if the email exists
+ def email_exists?(email)
+ emails.include?(email)
+ end
+
+ # Returns true if the preview exists
+ def exists?(preview)
+ all.any?{ |p| p.preview_name == preview }
+ end
+
+ # Find a mailer preview by its underscored class name
+ def find(preview)
+ all.find{ |p| p.preview_name == preview }
+ end
+
+ # Returns the underscored name of the mailer preview without the suffix
+ def preview_name
+ name.sub(/Preview$/, '').underscore
+ end
+
+ protected
+ def load_previews #:nodoc:
+ if preview_path?
+ Dir["#{preview_path}/**/*_preview.rb"].each{ |file| require_dependency file }
+ end
+ end
+
+ def preview_path #:nodoc:
+ Base.preview_path
+ end
+
+ def preview_path? #:nodoc:
+ Base.preview_path?
+ end
+ end
+ end
+end
diff --git a/actionmailer/lib/action_mailer/railtie.rb b/actionmailer/lib/action_mailer/railtie.rb
index 7677ff3a7c..c893ddfef5 100644
--- a/actionmailer/lib/action_mailer/railtie.rb
+++ b/actionmailer/lib/action_mailer/railtie.rb
@@ -19,6 +19,10 @@ module ActionMailer
options.javascripts_dir ||= paths["public/javascripts"].first
options.stylesheets_dir ||= paths["public/stylesheets"].first
+ if Rails.env.development?
+ options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
+ end
+
# make sure readers methods get compiled
options.asset_host ||= app.config.asset_host
options.relative_url_root ||= app.config.relative_url_root
@@ -40,5 +44,11 @@ module ActionMailer
config.compile_methods! if config.respond_to?(:compile_methods!)
end
end
+
+ config.after_initialize do
+ if ActionMailer::Base.preview_path?
+ ActiveSupport::Dependencies.autoload_paths << ActionMailer::Base.preview_path
+ end
+ end
end
end
diff --git a/actionmailer/lib/action_mailer/version.rb b/actionmailer/lib/action_mailer/version.rb
index 9d00091972..46eb763c26 100644
--- a/actionmailer/lib/action_mailer/version.rb
+++ b/actionmailer/lib/action_mailer/version.rb
@@ -1,7 +1,7 @@
module ActionMailer
# Returns the version of the currently loaded ActionMailer as a Gem::Version
def self.version
- Gem::Version.new "4.1.0.beta"
+ Gem::Version.new "4.1.0.beta1"
end
module VERSION #:nodoc: