Support multiple preview paths for mailers

This commit is contained in:
fatkodima 2017-12-28 17:45:44 +02:00
parent 92fa470aaa
commit 64ad045e47
12 changed files with 139 additions and 45 deletions

View File

@ -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.

View File

@ -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.

View File

@ -7,11 +7,11 @@ module ActionMailer
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 ActionMailer
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 @@ module ActionMailer
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

View File

@ -8,6 +8,7 @@ require "abstract_controller/railties/routes_helpers"
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 @@ module ActionMailer
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 @@ module ActionMailer
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 @@ module ActionMailer
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

View File

@ -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

View File

@ -1859,12 +1859,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`
@ -2986,6 +2986,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.

View File

@ -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
-------------------------------------

View File

@ -608,6 +608,13 @@ module Rails
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)

View File

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

View File

@ -55,7 +55,7 @@ module ApplicationTests
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 @@ module ApplicationTests
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 @@ module ApplicationTests
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")

View File

@ -53,6 +53,7 @@ module ApplicationTests
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

View File

@ -302,6 +302,30 @@ module RailtiesTest
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