# How to Add Dynamic Subdomain in Rails Application

For those who want to implement subdomain programmatically within your rails application, you can follow these few steps:

#### 1. Generate Account Model

First, let’s create an Account model as a table to store subdomain names that we will accept in our application.

```
rails g model Account subdomain:string
```

From the above generator, it generates a migration file. We can then do `rails db:migrate`.

#### 2. Add Request-based Constraints dan Modify routes.rb

Create a new file inside the **/lib** folder and give it the name, say **subdomain.rb**.

Add this code inside that file:

```
class Subdomain
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != "www"
  end
end
```

Then we need to modify a bit our **routes.rb** by adding `constraints` to every URLs that we will use under the subdomain. For an example, **pages_controller.rb** needs to be accessible under a specific subdomain, so we can write our route like this:

```
Rails.application.routes.draw do
  # For details on the DSL available within this file, see http://guides.rubyonrails.org/routing.html

  constraints(Subdomain) do

    get '/', to: 'pages#index'

  end

end
```

#### 3. Add Authorization to Controller

We will then need to add `before_action :require_subdomain` since the controllers need to be strictly accessible from the subdomain only. This is achievable by modifying our **application_controller.rb**:


```
class ApplicationController < ActionController::Base
  protect_from_forgery with: :exception
  helper_method :require_subdomain

  private

  def require_subdomain
    not_found unless subdomain_exist?
  end

  def subdomain_exist?
    account = Account.find_by_subdomain(request.subdomain)
    !!account
  end

  def not_found
    raise ActionController::RoutingError.new('404')
  end
end
```

In the **application_controller.rb**  above we now have a helper method called `require_subdomain`, which is reusable to each controller that requires to be authorized by the subdomain.

```
class PagesController < ApplicationController
  before_action :require_subdomain

  def index
    # controller logic goes here
  end
end
```

#### 4. Try It Out

Let's use rails console to create a dummy for our `Account` or subdomain.

```
$ rails c
Running via Spring preloader in process 15151
Loading development environment (Rails 6.0.0)
2.6.5 :001 > Account.new(subdomain: 'test').save
   (0.4ms)  SET NAMES utf8,  @@SESSION.sql_mode = CONCAT(CONCAT(@@sql_mode, ',STRICT_ALL_TABLES'), ',NO_AUTO_VALUE_ON_ZERO'),  @@SESSION.sql_auto_is_null = 0, @@SESSION.wait_timeout = 2147483
   (0.3ms)  BEGIN
  Account Exists (0.7ms)  SELECT  1 AS one FROM `accounts` WHERE `accounts`.`subdomain` = BINARY 'test' LIMIT 1
  SQL (0.5ms)  INSERT INTO `accounts` (`subdomain`, `created_at`, `updated_at`) VALUES ('test', '2017-07-22 14:58:35', '2017-07-22 14:58:35')
   (35.5ms)  COMMIT
 => true 
```

Open the browser then visit http://test.lvh.me:3000 and also try accessing some random subdomain, for example, http://doesnotexist.lvh.me:3000. 

About lvh.me domain, you can check [this article](https://nickjanetakis.com/blog/ngrok-lvhme-nipio-a-trilogy-for-local-development-and-testing) out

**If the subdomain is registered in `Account`**
 
![download (2).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1582159083799/SQvO1cAJ_.png)

**Subdomain doesn't exist in `Account`**


![download (1).png](https://cdn.hashnode.com/res/hashnode/image/upload/v1582158821554/VpK1Gf_tI.png)

**Tip:** 

We can add some extra validation layers in the `Account` creation so we can preserve some subdomain names so your user cannot claim those (i.e. www, admin, app, etc).

Thank you!

