aboutsummaryrefslogtreecommitdiffstats
path: root/actionmailer/lib/action_mailer/preview.rb
blob: 0b37f405eed3449be119e0fb62451aab9ccd2226 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
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"
      #
      mattr_accessor :preview_path, instance_writer: false

      # Enable or disable mailer previews through app configuration:
      #
      #     config.action_mailer.show_previews = true
      #
      # Defaults to true for development environment
      #
      mattr_accessor :show_previews, instance_writer: false

      # :nodoc:
      mattr_accessor :preview_interceptors, instance_writer: false
      self.preview_interceptors = [ActionMailer::InlinePreviewInterceptor]
    end

    module ClassMethods
      # Register one or more Interceptors which will be called before mail is previewed.
      def register_preview_interceptors(*interceptors)
        interceptors.flatten.compact.each { |interceptor| register_preview_interceptor(interceptor) }
      end

      # Unregister one or more previously registered Interceptors.
      def unregister_preview_interceptors(*interceptors)
        interceptors.flatten.compact.each { |interceptor| unregister_preview_interceptor(interceptor) }
      end

      # Register an Interceptor which will be called before mail is previewed.
      # Either a class or a string can be passed in as the Interceptor. If a
      # string is passed in it will be <tt>constantize</tt>d.
      def register_preview_interceptor(interceptor)
        preview_interceptor = find_class(interceptor)
        unless preview_interceptors.include?(preview_interceptor)
          preview_interceptors << preview_interceptor
        end
      end

      # Unregister a previously registered Interceptor.
      # Either a class or a string can be passed in as the Interceptor. If a
      # string is passed in it will be <tt>constantize</tt>d.
      def unregister_preview_interceptor(interceptor)
        preview_interceptor = find_class(interceptor)
        preview_interceptors.delete(preview_interceptor)
      end

      private

      def find_class(klass_or_string_or_symbol) #:nodoc:
        case klass_or_string_or_symbol
        when String, Symbol
          klass_or_string_or_symbol.to_s.camelize.constantize
        else
          klass_or_string_or_symbol
        end
      end
    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. The registered preview
      # interceptors will be informed so that they can transform the message
      # as they would if the mail was actually being delivered.
      def call(email)
        preview = self.new
        message = preview.public_send(email)
        inform_preview_interceptors(message)
        message
      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 show_previews #:nodoc:
          Base.show_previews
        end

        def inform_preview_interceptors(message) #:nodoc:
          Base.preview_interceptors.each do |interceptor|
            interceptor.previewing_email(message)
          end
        end
    end
  end
end