Маршрутизация Rails для обработки нескольких доменов в одном приложении

Я не смог найти работоспособного решения этой проблемы, несмотря на несколько подобных вопросов здесь и в других местах. Кажется вероятным, что на этот вопрос не было ответа для Rails 3, так что вот так:

У меня есть приложение, которое в настоящее время позволяет пользователям создавать свой собственный поддомен, который содержит их экземпляр приложения. В то время как в Rails 2 вам лучше всего использовать гем subdomain-fu, в версии 3 это значительно проще, чем в Railscast - http://railscasts.com/episodes/221-subdomains-in-rails-3.

Это хорошая вещь, но я также хочу предоставить пользователям возможность ассоциировать свое доменное имя с учетной записью. Поэтому, хотя у них может быть http://userx.mydomain.com, я бы хотел, чтобы они тоже связали http://userx.com.

Я нашел несколько ссылок на это в Rails 2, но эти методы больше не работают (особенно этот: https://feefighters.com/blog/hosting-multiple-domains-from-a-single-rails-app/).

Кто-нибудь может порекомендовать способ использования маршрутов для принятия произвольного домена и передачи его контроллеру, чтобы я мог показать соответствующий контент?

Обновление: я получил большинство ответов сейчас благодаря своевременному ответу Леонида и новому взгляду на код. В конечном итоге это потребовало дополнения к существующему коду субдомена, который я использовал (из решения Railscast), а затем добавило немного в rout.rb. Я еще не дошел, но хочу опубликовать то, что у меня есть.

В lib/subdomain.rb:

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

class Domain
  def self.matches?(request)
    request.domain.present? && request.domain != "mydomain.com"
  end
end

Я добавил второй класс в подражание первому, который, как известно, работает. Я просто добавляю условие, гарантирующее, что входящий домен не является тем, для которого я размещаю основной сайт.

Этот класс используется в rout.rb:

require 'subdomain'
constraints(Domain) do
  match '/' => 'blogs#show'
end

constraints(Subdomain) do
  match '/' => 'blogs#show'
end

Здесь я дополняю существующий код субдомена (опять же, он работает нормально) строфой для проверки домена. Если этот сервер отвечает на этот домен, а не тот, под которым работает основной сайт, перешлите к указанному контроллеру.

И хотя это, похоже, работает, у меня пока не все работает, но я думаю, что эта конкретная проблема была решена.

Ответ 1

Это действительно проще в Rails 3, в соответствии с http://guides.rubyonrails.org/routing.html#advanced-constraints:

1) определить собственный класс ограничений в lib/domain_constraint.rb:

class DomainConstraint
  def initialize(domain)
    @domains = [domain].flatten
  end

  def matches?(request)
    @domains.include? request.domain
  end
end

2) используйте класс в ваших маршрутах с новым синтаксисом блока

constraints DomainConstraint.new('mydomain.com') do
  root :to => 'mydomain#index'
end

root :to => 'main#index'

или старомодный синтаксис параметров

root :to => 'mydomain#index', :constraints => DomainConstraint.new('mydomain.com')

Ответ 2

В Rails 5 вы можете просто сделать это на своих маршрутах:

constraints subdomain: 'blogs' do
  match '/' => 'blogs#show'
end