ErwinM/acts_as_tenant

Issues with default_url_options

jimmypoulsen opened this issue · 5 comments

Hi! We're using ActsAsTenant to enable multi-tenancy in our application. Each tenant represents a market (eg Denmark, Finland ...). Each tenant has a host (eg "myapplication.dk" for Denmark, "myapplication.fi" for Finland ...). On each request, I override Rails' default URL options to ensure all links have the correct domain. However, sometimes our customers in Denmark experience being redirected to the Finnish site.

Here's my RequireTenant module. It's included in my base controller:

module RequireTenant
  extend ActiveSupport::Concern

  included do
    set_current_tenant_through_filter
    prepend_before_action :ensure_tenant!
  end

  def ensure_tenant!
    organization_tenant = Organization::Tenant.find_by(host: request.host)
    organization = organization_tenant.organization

    set_current_tenant(organization)
    Rails.application.routes.default_url_options[:host] = request.host
  rescue ActiveRecord::RecordNotFound => e
    set_test_tenant if Rails.env.test?
    set_development_tenant if Rails.env.development?
    render plain: "No tenant found for host: #{request.host}" if ActsAsTenant.current_tenant.nil?
  end

  def set_test_tenant
    set_current_tenant(Organization.find_by(country_code: 'DK'))
  end

  def set_development_tenant
    organization_tenant = Organization::Tenant.find_by!(host: 'app.lexly.dk.local')
    set_current_tenant(organization_tenant.organization)
    Rails.application.routes.default_url_options[:host] = request.host
  end
end

Can you guys see anything wrong with this code?

Ruby: 2.7.8
Rails: 6.0.3.3
ActsAsTenant: 0.5.1

There is a typo in find.by. It should be find_by in ...Organization::Tenant.find.by(host: request.host)

@anelcanto Sorry for that. That's not the error. I removed some code and rewrote it a bit to make it more clear for people in here what I'm trying to do.

Also, in the meantime, I searched a bit back and forth and noticed that I might have introduced a thread safety issue by modifying the global Rails.application.routes.default_url_options hash. To fix this I implemented the default_url_options in the module. Like this:

module RequireTenant
  ..

  def default_url_options
    { host: request.host }
  end

  ..

I think that ended up solving the issue. Waiting a couple more days to see.

Hi, I've got a similar situation. For now I've been using _path but I'd prefer to not have possible bugs if anyone uses _url, too.

Can you post your complete solution as reference?

FWIW, I found that just adding a protected method to ApplicationController appears to work

class ApplicationController < ActionController::Base
...
  protected
  
  def default_url_options
    { host: request.host }
  end

I worry about security, but I can't tell if my gut is right (and it is) or I'm just being paranoid, though. Obviously, I need to think through ActionMailer.default_url_options, too.

Rails and no single source of truth for default_url_options ... 😛

@wwvuillemot Sorry for the late reply here!

My solution is almost identical to yours. The only difference is that I put the default_url_options method inside a module (RequireTenant) which is included in my ApplicationController.