dubc15
dubc15

Reputation: 131

Rails 4 subdomains, tied to controller

grateful to have you guys as a resource! I think this should be a simple question but haven't been able to find a simple answer through searching yet, any help/guidance would be appreciated!! I have a "subdomain" controller which is setup in the following way:

get 'subdomain/:store' => 'subdomain#index'
get 'subdomain/:store/products' => 'subdomain#product_index'
get 'subdomain/:store/products/:id' => 'subdomain#products_show'

As you can see, the subdomain controller matches the request with a Store ID and can also get an index of all the associated products with the Store ID. I'd like to somehow convert each of these requests into a subdomain rather than a path. Each Store has a "subdomain" attribute (in the example below, one of the Store records has a subdomain value of "nike").

For example

host.com/subdomain/nike => nike.host.com
host.com/subdomain/nike/products => nike.host.com/products
host.com/subdomain/nike/products/5 => nike.host.com/products/5

Notice the controller "subdomain" was removed from the path. Any help? I looked into gems such as apartment but they look like they are way too complex for this. Also subdomain-fu but it looks like it's outdated for Rails 4. Thoughts? THANKS!

Upvotes: 1

Views: 1321

Answers (1)

CuriousMind
CuriousMind

Reputation: 34135

For this, you can add routing Constraint.

Add the file to lib/subdomain_required.rb

class SubdomainRequired
  def self.matches?(request)
    request.subdomain.present? && request.subdomain != 'www'
  end
end

Then, in your routes.rb, you can enclose your routes into a contraint block, somewhat like this:

constraints(SubdomainRequired) do
  get '/' => 'subdomain#index'
  get '/products' => 'subdomain#product_index'
  get '/products/:id' => 'subdomain#products_show'
end

Now the last step is to load the store based on subdomain which can be done using a before_action like this

class SubdomainController < ActionController::Base
  before_action :ensure_store!

  def index
   @products = current_store.products.all
  end

  def ensure_store!
    @store ||= Store.find_by subdomain: request.subdomain
    head(:not_found) if @store.nil?
    @store
  end

  def current_store
    @store
  end
end

now anywhere you want to get the store, you can use current_store helper method.

Hope it helps

Upvotes: 3

Related Questions