Skip to content

Commit 95066e5

Browse files
authored
Merge pull request rails#31595 from fatkodima/mailer-preview_paths
Support multiple preview paths for mailers
2 parents 22a0692 + 64ad045 commit 95066e5

File tree

12 files changed

+139
-45
lines changed

12 files changed

+139
-45
lines changed

actionmailer/CHANGELOG.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,9 @@
1+
* Support multiple preview paths for mailers.
12

3+
Option `config.action_mailer.preview_path` is deprecated in favor of
4+
`config.action_mailer.preview_paths`. Appending paths to this configuration option
5+
will cause those paths to be used in the search for mailer previews.
6+
7+
*fatkodima*
28

39
Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/actionmailer/CHANGELOG.md) for previous changes.

actionmailer/lib/action_mailer/base.rb

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -368,7 +368,7 @@ module ActionMailer
368368
# = Previewing emails
369369
#
370370
# You can preview your email templates visually by adding a mailer preview file to the
371-
# <tt>ActionMailer::Base.preview_path</tt>. Since most emails do something interesting
371+
# <tt>ActionMailer::Base.preview_paths</tt>. Since most emails do something interesting
372372
# with database data, you'll need to write some scenarios to load messages with fake data:
373373
#
374374
# class NotifierMailerPreview < ActionMailer::Preview
@@ -379,10 +379,10 @@ module ActionMailer
379379
#
380380
# Methods must return a <tt>Mail::Message</tt> object which can be generated by calling the mailer
381381
# method without the additional <tt>deliver_now</tt> / <tt>deliver_later</tt>. The location of the
382-
# mailer previews directory can be configured using the <tt>preview_path</tt> option which has a default
382+
# mailer preview directories can be configured using the <tt>preview_paths</tt> option which has a default
383383
# of <tt>test/mailers/previews</tt>:
384384
#
385-
# config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
385+
# config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
386386
#
387387
# An overview of all previews is accessible at <tt>http://localhost:3000/rails/mailers</tt>
388388
# on a running development server instance.

actionmailer/lib/action_mailer/preview.rb

Lines changed: 30 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,11 +7,11 @@ module Previews # :nodoc:
77
extend ActiveSupport::Concern
88

99
included do
10-
# Set the location of mailer previews through app configuration:
10+
# Add the location of mailer previews through app configuration:
1111
#
12-
# config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
12+
# config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
1313
#
14-
mattr_accessor :preview_path, instance_writer: false
14+
mattr_accessor :preview_paths, instance_writer: false, default: []
1515

1616
# Enable or disable mailer previews through app configuration:
1717
#
@@ -25,7 +25,31 @@ module Previews # :nodoc:
2525
mattr_accessor :preview_interceptors, instance_writer: false, default: [ActionMailer::InlinePreviewInterceptor]
2626
end
2727

28+
def preview_path
29+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
30+
Using preview_path option is deprecated and will be removed in Rails 7.2.
31+
Please use preview_paths instead.
32+
MSG
33+
self.class.preview_paths.first
34+
end
35+
2836
module ClassMethods
37+
def preview_path=(value)
38+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
39+
Using preview_path= option is deprecated and will be removed in Rails 7.2.
40+
Please use preview_paths= instead.
41+
MSG
42+
self.preview_paths << value
43+
end
44+
45+
def preview_path
46+
ActiveSupport::Deprecation.warn(<<-MSG.squish)
47+
Using preview_path option is deprecated and will be removed in Rails 7.2.
48+
Please use preview_paths instead.
49+
MSG
50+
self.preview_paths.first
51+
end
52+
2953
# Register one or more Interceptors which will be called before mail is previewed.
3054
def register_preview_interceptors(*interceptors)
3155
interceptors.flatten.compact.each { |interceptor| register_preview_interceptor(interceptor) }
@@ -119,13 +143,13 @@ def preview_name
119143

120144
private
121145
def load_previews
122-
if preview_path
146+
preview_paths.each do |preview_path|
123147
Dir["#{preview_path}/**/*_preview.rb"].sort.each { |file| require_dependency file }
124148
end
125149
end
126150

127-
def preview_path
128-
Base.preview_path
151+
def preview_paths
152+
Base.preview_paths
129153
end
130154

131155
def show_previews

actionmailer/lib/action_mailer/railtie.rb

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
module ActionMailer
99
class Railtie < Rails::Railtie # :nodoc:
1010
config.action_mailer = ActiveSupport::OrderedOptions.new
11+
config.action_mailer.preview_paths = []
1112
config.eager_load_namespaces << ActionMailer
1213

1314
initializer "action_mailer.logger" do
@@ -23,10 +24,7 @@ class Railtie < Rails::Railtie # :nodoc:
2324
options.stylesheets_dir ||= paths["public/stylesheets"].first
2425
options.show_previews = Rails.env.development? if options.show_previews.nil?
2526
options.cache_store ||= Rails.cache
26-
27-
if options.show_previews
28-
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
29-
end
27+
options.preview_paths |= ["#{Rails.root}/test/mailers/previews"]
3028

3129
# make sure readers methods get compiled
3230
options.asset_host ||= app.config.asset_host
@@ -40,6 +38,7 @@ class Railtie < Rails::Railtie # :nodoc:
4038
register_interceptors(options.delete(:interceptors))
4139
register_preview_interceptors(options.delete(:preview_interceptors))
4240
register_observers(options.delete(:observers))
41+
self.preview_paths |= options[:preview_paths]
4342

4443
if delivery_job = options.delete(:delivery_job)
4544
self.delivery_job = delivery_job.constantize
@@ -65,12 +64,9 @@ class Railtie < Rails::Railtie # :nodoc:
6564
end
6665
end
6766

68-
initializer "action_mailer.set_autoload_paths" do |app|
67+
initializer "action_mailer.set_autoload_paths", before: :set_autoload_paths do |app|
6968
options = app.config.action_mailer
70-
71-
if options.show_previews && options.preview_path
72-
ActiveSupport::Dependencies.autoload_paths << options.preview_path
73-
end
69+
app.config.paths["test/mailers/previews"].concat(options.preview_paths)
7470
end
7571

7672
initializer "action_mailer.compile_config_methods" do

guides/source/action_mailer_basics.md

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -556,12 +556,12 @@ visually see the new style instantly. A list of previews are also available
556556
in <http://localhost:3000/rails/mailers>.
557557
558558
By default, these preview classes live in `test/mailers/previews`.
559-
This can be configured using the `preview_path` option. For example, if you
560-
want to change it to `lib/mailer_previews`, you can configure it in
559+
This can be configured using the `preview_paths` option. For example, if you
560+
want to add `lib/mailer_previews` to it, you can configure it in
561561
`config/application.rb`:
562562
563563
```ruby
564-
config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
564+
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
565565
```
566566
567567
### Generating URLs in Action Mailer Views

guides/source/configuring.md

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1901,12 +1901,12 @@ Registers interceptors which will be called before mail is previewed.
19011901
config.action_mailer.preview_interceptors = ["MyPreviewMailInterceptor"]
19021902
```
19031903

1904-
#### `config.action_mailer.preview_path`
1904+
#### `config.action_mailer.preview_paths`
19051905

1906-
Specifies the location of mailer previews.
1906+
Specifies the locations of mailer previews. Appending paths to this configuration option will cause those paths to be used in the search for mailer previews.
19071907

19081908
```ruby
1909-
config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
1909+
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
19101910
```
19111911

19121912
#### `config.action_mailer.show_previews`
@@ -3039,6 +3039,8 @@ Below is a comprehensive list of all the initializers found in Rails in the orde
30393039
30403040
* `add_view_paths`: Adds the directory `app/views` from the application, railties, and engines to the lookup path for view files for the application.
30413041
3042+
* `add_mailer_preview_paths`: Adds the directory `test/mailers/previews` from the application, railties, and engines to the lookup path for mailer preview files for the application.
3043+
30423044
* `load_environment_config`: Loads the `config/environments` file for the current environment.
30433045
30443046
* `prepend_helpers_path`: Adds the directory `app/helpers` from the application, railties, and engines to the lookup path for helpers for the application.

guides/source/upgrading_ruby_on_rails.md

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,14 @@ If you don't want to use `SQLite3Adapter` in a strict mode, you can disable this
287287
config.active_record.sqlite3_adapter_strict_strings_by_default = false
288288
```
289289

290+
### Support multiple preview paths for `ActionMailer::Preview`
291+
292+
Option `config.action_mailer.preview_path` is deprecated in favor of `config.action_mailer.preview_paths`. Appending paths to this configuration option will cause those paths to be used in the search for mailer previews.
293+
294+
```ruby
295+
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
296+
```
297+
290298
Upgrading from Rails 6.1 to Rails 7.0
291299
-------------------------------------
292300

railties/lib/rails/engine.rb

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -608,6 +608,13 @@ def load_seed
608608
end
609609
end
610610

611+
initializer :add_mailer_preview_paths do
612+
previews = paths["test/mailers/previews"].existent
613+
unless previews.empty?
614+
ActiveSupport.on_load(:action_mailer) { self.preview_paths |= previews }
615+
end
616+
end
617+
611618
initializer :prepend_helpers_path do |app|
612619
if !isolated? || (app == self)
613620
app.config.helpers_paths.unshift(*paths["app/helpers"].existent)

railties/lib/rails/engine/configuration.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ def paths
6868
paths.add "vendor", load_path: true
6969
paths.add "vendor/assets", glob: "*"
7070

71+
paths.add "test/mailers/previews", eager_load: true
72+
7173
paths
7274
end
7375
end

railties/test/application/mailer_previews_test.rb

Lines changed: 45 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ def teardown
5555
assert_equal 200, last_response.status
5656
end
5757

58-
test "mailer previews are loaded from the default preview_path" do
58+
test "mailer previews are loaded from the default preview_paths" do
5959
mailer "notifier", <<-RUBY
6060
class Notifier < ActionMailer::Base
6161
default from: "[email protected]"
@@ -85,37 +85,41 @@ def foo
8585
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
8686
end
8787

88-
test "mailer previews are loaded from a custom preview_path" do
88+
test "mailer previews are loaded from custom preview_paths" do
8989
app_dir "lib/mailer_previews"
90-
add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'"
90+
add_to_config "config.action_mailer.preview_paths = ['#{app_path}/lib/notifier_previews', '#{app_path}/lib/confirm_previews']"
9191

92-
mailer "notifier", <<-RUBY
93-
class Notifier < ActionMailer::Base
94-
default from: "[email protected]"
92+
["notifier", "confirm"].each do |keyword|
93+
mailer keyword, <<-RUBY
94+
class #{keyword.camelize} < ActionMailer::Base
95+
default from: "[email protected]"
9596
96-
def foo
97-
mail to: "[email protected]"
97+
def foo
98+
mail to: "[email protected]"
99+
end
98100
end
99-
end
100-
RUBY
101+
RUBY
101102

102-
text_template "notifier/foo", <<-RUBY
103-
Hello, World!
104-
RUBY
103+
text_template "#{keyword}/foo", <<-RUBY
104+
Hello, World!
105+
RUBY
105106

106-
app_file "lib/mailer_previews/notifier_preview.rb", <<-RUBY
107-
class NotifierPreview < ActionMailer::Preview
108-
def foo
109-
Notifier.foo
107+
app_file "lib/#{keyword}_previews/notifier_preview.rb", <<-RUBY
108+
class #{keyword.camelize}Preview < ActionMailer::Preview
109+
def foo
110+
#{keyword.camelize}.foo
111+
end
110112
end
111-
end
112-
RUBY
113+
RUBY
114+
end
113115

114116
app("development")
115117

116118
get "/rails/mailers"
117119
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
118120
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
121+
assert_match '<h3><a href="/rails/mailers/confirm">Confirm</a></h3>', last_response.body
122+
assert_match '<li><a href="/rails/mailers/confirm/foo">foo</a></li>', last_response.body
119123
end
120124

121125
test "mailer previews are reloaded across requests" do
@@ -255,9 +259,29 @@ def foo
255259
assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body
256260
end
257261

258-
test "mailer previews are reloaded from a custom preview_path" do
262+
test "mailer preview_path option is deprecated" do
263+
prev = ActionMailer::Base.preview_paths
264+
ActionMailer::Base.preview_paths = ["#{app_path}/lib/mailer/previews"]
265+
assert_deprecated do
266+
assert "#{app_path}/lib/mailer/previews", ActionMailer::Base.preview_path
267+
end
268+
ensure
269+
ActionMailer::Base.preview_paths = prev
270+
end
271+
272+
test "mailer preview_path= option is deprecated" do
273+
prev = ActionMailer::Base.preview_paths
274+
assert_deprecated do
275+
ActionMailer::Base.preview_path = "#{app_path}/lib/mailer/previews"
276+
end
277+
assert ["#{app_path}/lib/mailer/previews"], ActionMailer::Base.preview_paths
278+
ensure
279+
ActionMailer::Base.preview_paths = prev
280+
end
281+
282+
test "mailer previews are reloaded from custom preview_paths" do
259283
app_dir "lib/mailer_previews"
260-
add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'"
284+
add_to_config "config.action_mailer.preview_paths = ['#{app_path}/lib/mailer_previews']"
261285

262286
app("development")
263287

0 commit comments

Comments
 (0)