From 0971de1ffdf3a1df5859a95a95d5472688673004 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Tue, 22 Nov 2022 00:58:56 +0100 Subject: [PATCH 1/3] Bump view_component from 2.69.0 to 2.78.0 ViewComponent 2.78.0 adds support for variants with dashes and dots in their names; since we're going to add variants named after a subdomain, we need this feature. --- Gemfile | 2 +- Gemfile.lock | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Gemfile b/Gemfile index 9b752642f..f8b93ec3c 100644 --- a/Gemfile +++ b/Gemfile @@ -60,7 +60,7 @@ gem "turbolinks", "~> 5.2.1" gem "turnout", "~> 2.5.0" gem "uglifier", "~> 4.2.0" gem "uuidtools", "~> 2.2.0" -gem "view_component", "~> 2.69.0" +gem "view_component", "~> 2.78.0" gem "whenever", "~> 1.0.0", require: false gem "wicked_pdf", "~> 2.6.3" gem "wkhtmltopdf-binary", "~> 0.12.6" diff --git a/Gemfile.lock b/Gemfile.lock index ce716d9cc..373f0d7bc 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -678,7 +678,7 @@ GEM unicode-display_width (2.2.0) uniform_notifier (1.16.0) uuidtools (2.2.0) - view_component (2.69.0) + view_component (2.78.0) activesupport (>= 5.0.0, < 8.0) concurrent-ruby (~> 1.0) method_source (~> 1.0) @@ -810,7 +810,7 @@ DEPENDENCIES turnout (~> 2.5.0) uglifier (~> 4.2.0) uuidtools (~> 2.2.0) - view_component (~> 2.69.0) + view_component (~> 2.78.0) web-console (~> 4.2.0) webdrivers (~> 4.7.0) whenever (~> 1.0.0) From 18611f32f14694a55fc585dda4ad4186400587e1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Thu, 3 Nov 2022 00:10:28 +0100 Subject: [PATCH 2/3] Allow rendering different views per tenant Sometimes it might be convenient to use completely different views for different tenants. For example, a certain tenant might use a footer that has nothing to do with the default one. For these cases, instead of adding `case Tenant.current_schema` conditions to the view, it might be tidier to use a different file. For this purpose, we're using Rails variants [1], which means that a tenant named `mytenant` will use a template ending with `.html+mytenant.erb` if it's available. This works with components too, but has a limitation: when using the `custom/` folder to add ERB files for a tenant, the default tenant ERB file needs to be added to the `custom/` folder as well; if there aren't changes to this file, a symbolic link will do. For example, if we're writing a custom `admin/action_component` view for the tenant `milky-way` but don't need to change this file for the default tenant: 1. Create `app/components/custom/admin/action_component.rb` according to the components customizations documentation [2] 2. Create the custom view for the `milky-way` tenant and save it under `app/components/custom/admin/action_component.html+milky-way.erb` 3. Enter the `app/components/custom/admin/` folder and run `ln -s ../../admin/action_component.html.erb` We're also adding some controller tests. Since Rails doesn't load the middleware during controller tests, we're stubbing the `current_schema` method directly instead of changing the subdomain of the request. [1] https://guides.rubyonrails.org/v6.0/layouts_and_rendering.html#the-variants-option [2] https://docs.consulproject.org/docs/english-documentation/customization/components --- app/controllers/application_controller.rb | 1 + app/controllers/concerns/tenant_variants.rb | 13 +++++++++++ app/controllers/management/base_controller.rb | 1 + .../management/sessions_controller.rb | 1 + .../concerns/tenant_variants_spec.rb | 23 +++++++++++++++++++ 5 files changed, 39 insertions(+) create mode 100644 app/controllers/concerns/tenant_variants.rb create mode 100644 spec/controllers/concerns/tenant_variants_spec.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index fd9c77a6a..acd3ba587 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,6 +1,7 @@ require "application_responder" class ApplicationController < ActionController::Base + include TenantVariants include GlobalizeFallbacks include HasFilters include HasOrders diff --git a/app/controllers/concerns/tenant_variants.rb b/app/controllers/concerns/tenant_variants.rb new file mode 100644 index 000000000..6475e7d9b --- /dev/null +++ b/app/controllers/concerns/tenant_variants.rb @@ -0,0 +1,13 @@ +module TenantVariants + extend ActiveSupport::Concern + + included do + before_action :set_tenant_variant + end + + private + + def set_tenant_variant + request.variant = Tenant.current_schema.to_sym + end +end diff --git a/app/controllers/management/base_controller.rb b/app/controllers/management/base_controller.rb index 81afa78e4..f426cbd3c 100644 --- a/app/controllers/management/base_controller.rb +++ b/app/controllers/management/base_controller.rb @@ -1,4 +1,5 @@ class Management::BaseController < ActionController::Base + include TenantVariants include GlobalizeFallbacks layout "management" default_form_builder ConsulFormBuilder diff --git a/app/controllers/management/sessions_controller.rb b/app/controllers/management/sessions_controller.rb index 84d9d1265..2a36ded0a 100644 --- a/app/controllers/management/sessions_controller.rb +++ b/app/controllers/management/sessions_controller.rb @@ -1,6 +1,7 @@ require "manager_authenticator" class Management::SessionsController < ActionController::Base + include TenantVariants include GlobalizeFallbacks include AccessDeniedHandler default_form_builder ConsulFormBuilder diff --git a/spec/controllers/concerns/tenant_variants_spec.rb b/spec/controllers/concerns/tenant_variants_spec.rb new file mode 100644 index 000000000..46e949254 --- /dev/null +++ b/spec/controllers/concerns/tenant_variants_spec.rb @@ -0,0 +1,23 @@ +require "rails_helper" + +describe TenantVariants do + controller(ActionController::Base) do + include TenantVariants + + def index + render plain: request.variant + end + end + + it "uses the default tenant by default" do + get :index + expect(response.body).to eq "[:public]" + end + + it "uses the current tenant schema when defined" do + allow(Tenant).to receive(:current_schema).and_return("random-name") + + get :index + expect(response.body).to eq '[:"random-name"]' + end +end From d579bcce2dd1f195fdaa8635d45d1b140fab818a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Javi=20Mart=C3=ADn?= Date: Mon, 28 Nov 2022 19:40:50 +0100 Subject: [PATCH 3/3] Allow rendering different email views per tenant We were assigning variants in a controller, in the context of a request. However, when sending emails, there is no request and no controller is involved, so we also need to set the variant in the ApplicationMailer class. --- app/mailers/application_mailer.rb | 5 +++++ spec/mailers/application_mailer_spec.rb | 18 ++++++++++++++++++ 2 files changed, 23 insertions(+) diff --git a/app/mailers/application_mailer.rb b/app/mailers/application_mailer.rb index 1fc1410e0..1fd9a1c47 100644 --- a/app/mailers/application_mailer.rb +++ b/app/mailers/application_mailer.rb @@ -3,6 +3,7 @@ class ApplicationMailer < ActionMailer::Base default from: proc { "#{Setting["mailer_from_name"]} <#{Setting["mailer_from_address"]}>" } layout "mailer" before_action :set_asset_host + before_action :set_variant after_action :set_smtp_settings def default_url_options @@ -13,6 +14,10 @@ class ApplicationMailer < ActionMailer::Base self.asset_host ||= root_url.delete_suffix("/") end + def set_variant + lookup_context.variants = [Tenant.current_schema.to_sym] + end + def set_smtp_settings unless Tenant.default? mail.delivery_method.settings.merge!(Tenant.current_secrets.smtp_settings.to_h) diff --git a/spec/mailers/application_mailer_spec.rb b/spec/mailers/application_mailer_spec.rb index 665dcca53..211c8f8ed 100644 --- a/spec/mailers/application_mailer_spec.rb +++ b/spec/mailers/application_mailer_spec.rb @@ -78,4 +78,22 @@ describe ApplicationMailer do end end end + + describe "#set_variant" do + let(:mailer) { ApplicationMailer.new } + + it "uses the default tenant by default" do + mailer.set_variant + + expect(mailer.lookup_context.variants).to eq [:public] + end + + it "uses the current tenant schema when defined" do + allow(Tenant).to receive(:current_schema).and_return("random-name") + + mailer.set_variant + + expect(mailer.lookup_context.variants).to eq [:"random-name"] + end + end end