diff --git a/NEWS.md b/NEWS.md index 7f21e8fa9..1a31f1e23 100644 --- a/NEWS.md +++ b/NEWS.md @@ -13,6 +13,7 @@ Unreleased * Introduce `suspenders:setup` generator * Introduce `suspenders:tasks` generator * Introduce `suspenders:db:migrate` task +* Introduce `suspenders:email` generator 20230113.0 (January, 13, 2023) diff --git a/README.md b/README.md index 820ccdec1..0f1a43568 100644 --- a/README.md +++ b/README.md @@ -159,6 +159,20 @@ bin/rails suspenders:rake bin/rails suspenders:db:migrate ``` +### Email + +Intercepts emails in non-production environments by setting `INTERCEPTOR_ADDRESSES`. + +```sh +INTERCEPTOR_ADDRESSES="user_1@example.com,user_2@example.com" bin/rails s +``` + +Configures `default_url_options` in `test` and `development`. + +``` +bin/rails g suspenders:email +``` + ## Contributing See the [CONTRIBUTING] document. diff --git a/lib/generators/suspenders/email_generator.rb b/lib/generators/suspenders/email_generator.rb new file mode 100644 index 000000000..f00e3bf82 --- /dev/null +++ b/lib/generators/suspenders/email_generator.rb @@ -0,0 +1,52 @@ +module Suspenders + module Generators + class EmailGenerator < Rails::Generators::Base + source_root File.expand_path("../../templates/email", __FILE__) + desc <<~TEXT + Intercepts emails in non-production environments by setting `INTERCEPTOR_ADDRESSES`. + + ```sh + INTERCEPTOR_ADDRESSES="user_1@example.com,user_2@example.com" bin/rails s + ``` + + Configures `default_url_options` in `test` and `development`. + TEXT + + def create_email_interceptor + copy_file "email_interceptor.rb", "app/mailers/email_interceptor.rb" + end + + def create_email_interceptor_initializer + initializer "email_interceptor.rb", <<~RUBY + Rails.application.configure do + if ENV["INTERCEPTOR_ADDRESSES"].present? + config.action_mailer.interceptors = %w[EmailInterceptor] + end + end + RUBY + end + + def configure_email_interceptor + environment do + %( + config.to_prepare do + EmailInterceptor.config.interceptor_addresses = ENV.fetch("INTERCEPTOR_ADDRESSES", "").split(",") + end + ) + end + end + + # TODO: Remove once https://github.com/rails/rails/pull/51191 is in latest + # Rails release + def configure_development_environment + environment %(config.action_mailer.default_url_options = { host: "localhost", port: 3000 }), env: "development" + end + + # TODO: Remove once https://github.com/rails/rails/pull/51191 is in latest + # Rails release + def configure_test_environment + environment %(config.action_mailer.default_url_options = { host: "www.example.com" }), env: "test" + end + end + end +end diff --git a/lib/generators/templates/email/email_interceptor.rb b/lib/generators/templates/email/email_interceptor.rb new file mode 100644 index 000000000..8ad791abd --- /dev/null +++ b/lib/generators/templates/email/email_interceptor.rb @@ -0,0 +1,11 @@ +class EmailInterceptor + include ActiveSupport::Configurable + + config_accessor :interceptor_addresses, default: [] + + def self.delivering_email(message) + to = interceptor_addresses + + message.to = to if to.any? + end +end diff --git a/test/generators/suspenders/email_generator_test.rb b/test/generators/suspenders/email_generator_test.rb new file mode 100644 index 000000000..31ca581e4 --- /dev/null +++ b/test/generators/suspenders/email_generator_test.rb @@ -0,0 +1,91 @@ +require "test_helper" +require "generators/suspenders/email_generator" + +module Suspenders + module Generators + class EmailGeneratorTest < Rails::Generators::TestCase + include Suspenders::TestHelpers + + tests Suspenders::Generators::EmailGenerator + destination Rails.root + setup :prepare_destination + teardown :restore_destination + + test "creates a mailer intercepter" do + expected = <<~RUBY + class EmailInterceptor + include ActiveSupport::Configurable + + config_accessor :interceptor_addresses, default: [] + + def self.delivering_email(message) + to = interceptor_addresses + + message.to = to if to.any? + end + end + RUBY + + run_generator + + assert_file app_root("app/mailers/email_interceptor.rb") do |file| + assert_equal expected, file + end + end + + test "creates initializer" do + expected = <<~RUBY + Rails.application.configure do + if ENV["INTERCEPTOR_ADDRESSES"].present? + config.action_mailer.interceptors = %w[EmailInterceptor] + end + end + RUBY + + run_generator + + assert_file app_root("config/initializers/email_interceptor.rb") do |file| + assert_equal expected, file + end + end + + test "configures application to user email intercepter" do + run_generator + + assert_file app_root("config/application.rb"), /config\.to_prepare\s*do.\s*EmailInterceptor\.config\.interceptor_addresses\s*=\s*ENV\.fetch\("INTERCEPTOR_ADDRESSES",\s*\"\"\)\.split\(\",\"\).\s*end/m + end + + test "configures action mailer in development" do + run_generator + + assert_file app_root("config/environments/development.rb"), /config\.action_mailer\.default_url_options\s*=\s*{\s*host:\s*"localhost",\s*port:\s*3000\s*}/ + end + + test "configures action mailer in test" do + run_generator + + assert_file app_root("config/environments/test.rb"), /config\.action_mailer\.default_url_options\s*=\s*{\s*host:\s*"www\.example\.com"\s*}/ + end + + test "has custom description" do + assert_no_match(/Description/, generator_class.desc) + end + + private + + def prepare_destination + backup_file "config/application.rb" + backup_file "config/environments/development.rb" + backup_file "config/environments/test.rb" + end + + def restore_destination + restore_file "config/application.rb" + restore_file "config/environments/development.rb" + restore_file "config/environments/test.rb" + remove_file_if_exists "app/mailers/email_interceptor.rb" + remove_file_if_exists "config/initializers/email_interceptor.rb" + end + end + end +end