Merge pull request #31595 from fatkodima/mailer-preview_paths

Support multiple preview paths for mailers
This commit is contained in:
Rafael Mendonça França 2022-08-09 16:20:18 -03:00 committed by GitHub
commit 95066e5fbd
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 139 additions and 45 deletions

@ -1,3 +1,9 @@
* Support multiple preview paths for mailers.
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.
*fatkodima*
Please check [7-0-stable](https://github.com/rails/rails/blob/7-0-stable/actionmailer/CHANGELOG.md) for previous changes.

@ -368,7 +368,7 @@ module ActionMailer
# = 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
# <tt>ActionMailer::Base.preview_paths</tt>. Since most emails do something interesting
# with database data, you'll need to write some scenarios to load messages with fake data:
#
# class NotifierMailerPreview < ActionMailer::Preview
@ -379,10 +379,10 @@ module ActionMailer
#
# Methods must return a <tt>Mail::Message</tt> object which can be generated by calling the mailer
# method without the additional <tt>deliver_now</tt> / <tt>deliver_later</tt>. The location of the
# mailer previews directory can be configured using the <tt>preview_path</tt> option which has a default
# mailer preview directories can be configured using the <tt>preview_paths</tt> option which has a default
# of <tt>test/mailers/previews</tt>:
#
# config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
# config.action_mailer.preview_paths << "#{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.

@ -7,11 +7,11 @@ module Previews # :nodoc:
extend ActiveSupport::Concern
included do
# Set the location of mailer previews through app configuration:
# Add the location of mailer previews through app configuration:
#
# config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
# config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
#
mattr_accessor :preview_path, instance_writer: false
mattr_accessor :preview_paths, instance_writer: false, default: []
# Enable or disable mailer previews through app configuration:
#
@ -25,7 +25,31 @@ module Previews # :nodoc:
mattr_accessor :preview_interceptors, instance_writer: false, default: [ActionMailer::InlinePreviewInterceptor]
end
def preview_path
ActiveSupport::Deprecation.warn(<<-MSG.squish)
Using preview_path option is deprecated and will be removed in Rails 7.2.
Please use preview_paths instead.
MSG
self.class.preview_paths.first
end
module ClassMethods
def preview_path=(value)
ActiveSupport::Deprecation.warn(<<-MSG.squish)
Using preview_path= option is deprecated and will be removed in Rails 7.2.
Please use preview_paths= instead.
MSG
self.preview_paths << value
end
def preview_path
ActiveSupport::Deprecation.warn(<<-MSG.squish)
Using preview_path option is deprecated and will be removed in Rails 7.2.
Please use preview_paths instead.
MSG
self.preview_paths.first
end
# 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) }
@ -119,13 +143,13 @@ def preview_name
private
def load_previews
if preview_path
preview_paths.each do |preview_path|
Dir["#{preview_path}/**/*_preview.rb"].sort.each { |file| require_dependency file }
end
end
def preview_path
Base.preview_path
def preview_paths
Base.preview_paths
end
def show_previews

@ -8,6 +8,7 @@
module ActionMailer
class Railtie < Rails::Railtie # :nodoc:
config.action_mailer = ActiveSupport::OrderedOptions.new
config.action_mailer.preview_paths = []
config.eager_load_namespaces << ActionMailer
initializer "action_mailer.logger" do
@ -23,10 +24,7 @@ class Railtie < Rails::Railtie # :nodoc:
options.stylesheets_dir ||= paths["public/stylesheets"].first
options.show_previews = Rails.env.development? if options.show_previews.nil?
options.cache_store ||= Rails.cache
if options.show_previews
options.preview_path ||= defined?(Rails.root) ? "#{Rails.root}/test/mailers/previews" : nil
end
options.preview_paths |= ["#{Rails.root}/test/mailers/previews"]
# make sure readers methods get compiled
options.asset_host ||= app.config.asset_host
@ -40,6 +38,7 @@ class Railtie < Rails::Railtie # :nodoc:
register_interceptors(options.delete(:interceptors))
register_preview_interceptors(options.delete(:preview_interceptors))
register_observers(options.delete(:observers))
self.preview_paths |= options[:preview_paths]
if delivery_job = options.delete(:delivery_job)
self.delivery_job = delivery_job.constantize
@ -65,12 +64,9 @@ class Railtie < Rails::Railtie # :nodoc:
end
end
initializer "action_mailer.set_autoload_paths" do |app|
initializer "action_mailer.set_autoload_paths", before: :set_autoload_paths do |app|
options = app.config.action_mailer
if options.show_previews && options.preview_path
ActiveSupport::Dependencies.autoload_paths << options.preview_path
end
app.config.paths["test/mailers/previews"].concat(options.preview_paths)
end
initializer "action_mailer.compile_config_methods" do

@ -556,12 +556,12 @@ visually see the new style instantly. A list of previews are also available
in <http://localhost:3000/rails/mailers>.
By default, these preview classes live in `test/mailers/previews`.
This can be configured using the `preview_path` option. For example, if you
want to change it to `lib/mailer_previews`, you can configure it in
This can be configured using the `preview_paths` option. For example, if you
want to add `lib/mailer_previews` to it, you can configure it in
`config/application.rb`:
```ruby
config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
```
### Generating URLs in Action Mailer Views

@ -1901,12 +1901,12 @@ Registers interceptors which will be called before mail is previewed.
config.action_mailer.preview_interceptors = ["MyPreviewMailInterceptor"]
```
#### `config.action_mailer.preview_path`
#### `config.action_mailer.preview_paths`
Specifies the location of mailer previews.
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.
```ruby
config.action_mailer.preview_path = "#{Rails.root}/lib/mailer_previews"
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
```
#### `config.action_mailer.show_previews`
@ -3039,6 +3039,8 @@ Below is a comprehensive list of all the initializers found in Rails in the orde
* `add_view_paths`: Adds the directory `app/views` from the application, railties, and engines to the lookup path for view files for the application.
* `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.
* `load_environment_config`: Loads the `config/environments` file for the current environment.
* `prepend_helpers_path`: Adds the directory `app/helpers` from the application, railties, and engines to the lookup path for helpers for the application.

@ -287,6 +287,14 @@ If you don't want to use `SQLite3Adapter` in a strict mode, you can disable this
config.active_record.sqlite3_adapter_strict_strings_by_default = false
```
### Support multiple preview paths for `ActionMailer::Preview`
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.
```ruby
config.action_mailer.preview_paths << "#{Rails.root}/lib/mailer_previews"
```
Upgrading from Rails 6.1 to Rails 7.0
-------------------------------------

@ -608,6 +608,13 @@ def load_seed
end
end
initializer :add_mailer_preview_paths do
previews = paths["test/mailers/previews"].existent
unless previews.empty?
ActiveSupport.on_load(:action_mailer) { self.preview_paths |= previews }
end
end
initializer :prepend_helpers_path do |app|
if !isolated? || (app == self)
app.config.helpers_paths.unshift(*paths["app/helpers"].existent)

@ -68,6 +68,8 @@ def paths
paths.add "vendor", load_path: true
paths.add "vendor/assets", glob: "*"
paths.add "test/mailers/previews", eager_load: true
paths
end
end

@ -55,7 +55,7 @@ def teardown
assert_equal 200, last_response.status
end
test "mailer previews are loaded from the default preview_path" do
test "mailer previews are loaded from the default preview_paths" do
mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
@ -85,37 +85,41 @@ def foo
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
end
test "mailer previews are loaded from a custom preview_path" do
test "mailer previews are loaded from custom preview_paths" do
app_dir "lib/mailer_previews"
add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'"
add_to_config "config.action_mailer.preview_paths = ['#{app_path}/lib/notifier_previews', '#{app_path}/lib/confirm_previews']"
mailer "notifier", <<-RUBY
class Notifier < ActionMailer::Base
default from: "from@example.com"
["notifier", "confirm"].each do |keyword|
mailer keyword, <<-RUBY
class #{keyword.camelize} < ActionMailer::Base
default from: "from@example.com"
def foo
mail to: "to@example.org"
def foo
mail to: "to@example.org"
end
end
end
RUBY
RUBY
text_template "notifier/foo", <<-RUBY
Hello, World!
RUBY
text_template "#{keyword}/foo", <<-RUBY
Hello, World!
RUBY
app_file "lib/mailer_previews/notifier_preview.rb", <<-RUBY
class NotifierPreview < ActionMailer::Preview
def foo
Notifier.foo
app_file "lib/#{keyword}_previews/notifier_preview.rb", <<-RUBY
class #{keyword.camelize}Preview < ActionMailer::Preview
def foo
#{keyword.camelize}.foo
end
end
end
RUBY
RUBY
end
app("development")
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/notifier">Notifier</a></h3>', last_response.body
assert_match '<li><a href="/rails/mailers/notifier/foo">foo</a></li>', last_response.body
assert_match '<h3><a href="/rails/mailers/confirm">Confirm</a></h3>', last_response.body
assert_match '<li><a href="/rails/mailers/confirm/foo">foo</a></li>', last_response.body
end
test "mailer previews are reloaded across requests" do
@ -255,9 +259,29 @@ def foo
assert_no_match '<li><a href="/rails/mailers/notifier/bar">bar</a></li>', last_response.body
end
test "mailer previews are reloaded from a custom preview_path" do
test "mailer preview_path option is deprecated" do
prev = ActionMailer::Base.preview_paths
ActionMailer::Base.preview_paths = ["#{app_path}/lib/mailer/previews"]
assert_deprecated do
assert "#{app_path}/lib/mailer/previews", ActionMailer::Base.preview_path
end
ensure
ActionMailer::Base.preview_paths = prev
end
test "mailer preview_path= option is deprecated" do
prev = ActionMailer::Base.preview_paths
assert_deprecated do
ActionMailer::Base.preview_path = "#{app_path}/lib/mailer/previews"
end
assert ["#{app_path}/lib/mailer/previews"], ActionMailer::Base.preview_paths
ensure
ActionMailer::Base.preview_paths = prev
end
test "mailer previews are reloaded from custom preview_paths" do
app_dir "lib/mailer_previews"
add_to_config "config.action_mailer.preview_path = '#{app_path}/lib/mailer_previews'"
add_to_config "config.action_mailer.preview_paths = ['#{app_path}/lib/mailer_previews']"
app("development")

@ -53,6 +53,7 @@ def assert_not_in_load_path(*path)
assert_path @paths["config/environments"], "config/environments/development.rb"
assert_path @paths["config/routes.rb"], "config/routes.rb"
assert_path @paths["config/routes"], "config/routes"
assert_path @paths["test/mailers/previews"], "test/mailers/previews"
assert_equal root("app", "controllers"), @paths["app/controllers"].expanded.first
end

@ -302,6 +302,30 @@ def index
assert_equal "Hi bukkits\n", response[2].body
end
test "adds its mailer previews to mailer preview paths" do
@plugin.write "app/mailers/bukkit_mailer.rb", <<-RUBY
class BukkitMailer < ActionMailer::Base
def foo
end
end
RUBY
@plugin.write "test/mailers/previews/bukkit_mailer_preview.rb", <<-RUBY
class BukkitMailerPreview < ActionMailer::Preview
def foo
end
end
RUBY
@plugin.write "app/views/bukkit_mailer/foo.html.erb", "Bukkit"
boot_rails
get "/rails/mailers"
assert_match '<h3><a href="/rails/mailers/bukkit_mailer">Bukkit Mailer</a></h3>', last_response.body
assert_match '<li><a href="/rails/mailers/bukkit_mailer/foo">foo</a></li>', last_response.body
end
test "adds helpers to controller views" do
@plugin.write "app/controllers/bukkit_controller.rb", <<-RUBY
class BukkitController < ActionController::Base