Code parsing domain names must anticipate variable lengths for TLD

This is part of the Semicolon&Sons Code Diary - consisting of lessons learned on the job. You're in the web-development category.

Last Updated: 2024-04-19

In my development environment I had the following for my domain:

en-au.lvh.me

In production I had:

en-au.oxbridgenotes.co.uk

I had code to calculate the current_country based on the domain name:

current_country = request.subdomain.downcase.match(/en-(\w+)/)

The code above worked in development and test environments, but not in production. What was up?

The issue was that in development, the URL had three dot-separated components en-au.lvh.me ("en-au", "lvh", "me"), but in production it had four en-au.oxbridgenotes.co.uk ("en-au", "oxbridgenotes", "co", "uk").

The Rails request methods like domain and subdomain assume the standard case of x.y for domains (excluding sub-domains) which it calls tld_length of 1.

The trick for me was to make tld_length environmentally dependent and cater for the difference in size between .co.uk and .me

# production
config.action_dispatch.tld_length = 2 # dev would only be 1

Here is what would happen if you manually passed in this number:

ActionDispatch::Request.new('HTTP_HOST' => 'www.domain.co.uk').domain(2)
=> "domain.co.uk" # www is missing
 ActionDispatch::Request.new('HTTP_HOST' => 'www.domain.co.uk').domain(3)
=> "www.domain.co.uk" # everything is preserved

Lesson: