Routing Railsów do obsługi wielu domen w jednej aplikacji

90

Nie udało mi się znaleźć praktycznego rozwiązania tego problemu, pomimo kilku podobnych pytań tutaj i gdzie indziej. Wydaje się prawdopodobne, że na to pytanie nie udzielono odpowiedzi w przypadku Rails 3, więc oto:

Mam aplikację, która obecnie umożliwia użytkownikom tworzenie własnej subdomeny zawierającej ich wystąpienie aplikacji. Podczas gdy w Railsach 2 najlepiej obsługiwano Cię przy użyciu klejnotu subdomain-fu, w wersji 3 jest to znacznie prostsze, jak na Railscast - http://railscasts.com/episodes/221-subdomains-in-rails-3 .

To dobra rzecz, ale chcę również zapewnić użytkownikom opcję kojarzenia własnej nazwy domeny z kontem. Więc chociaż mogą mieć adres http://użytkownik.moja_domena.com , chciałbym, aby również mieli skojarzony adres http://userx.com .

Znalazłem kilka odniesień do robienia tego w Railsach 2, ale te techniki wydają się już nie działać (szczególnie ta: https://feefighters.com/blog/hosting-multiple-domains-from-a-single-rails -app / ).

Czy ktoś może polecić sposób użycia tras w celu zaakceptowania dowolnej domeny i przekazania jej do kontrolera, abym mógł wyświetlić odpowiednią zawartość?

Aktualizacja : otrzymałem większość odpowiedzi teraz, dzięki szybkiej odpowiedzi Leonida i świeżemu spojrzeniu na kod. Ostatecznie wymagało to dodania do istniejącego kodu subdomeny, którego używałem (z rozwiązania Railscast), a następnie dodania trochę do route.rb. Nie jestem jeszcze do końca, ale chcę opublikować to, co mam do tej pory.

W 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

Dodałem drugą klasę naśladując pierwszą, która jest znana z pracy. Po prostu dodaję warunek, który zapewni, że domena przychodząca nie jest tą, dla której hostuję witrynę główną.

Ta klasa jest używana w route.rb:

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

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

Tutaj wklejam istniejący kod subdomeny (znowu działa dobrze) z sekcją do sprawdzenia domeny. Jeśli ten serwer odpowiada tej domenie i nie jest to ten, pod którym działa główna lokacja, przekieruj do określonego kontrolera.

I chociaż wydaje się, że to działa, nie mam jeszcze całej sprawy, ale myślę, że ten konkretny problem został rozwiązany.

Aaron Vegh
źródło
1
Dziękuję bardzo za twoją edycję, Aaron. Mam teraz do czynienia z dokładnie tą samą sytuacją. Jako pytanie uzupełniające, w jaki sposób możesz sprawić, aby serwer akceptował dowolną domenę, która jest do niego przekazywana? Zakładam, że będzie to ustawienie w pliku .conf, ale nie jestem pewien co. Każda pomoc będzie mile widziana!
deadwards
Aaron, jestem z tobą. Chcę zrobić to samo. Ale nie chcę zakodować domeny na stałe. Chcę, aby wszystko odbywało się programowo bez plików stref i ponownego uruchamiania serwera WWW.
Michael K Madison,
1
Michael, musisz odwrócić ten problem. Wyraźnie zadeklaruj i zakoduj na stałe trasy, które są przeznaczone wyłącznie dla Twojej aplikacji (np. Rejestracja) z ograniczeniem hosta lub subdomeny, a następnie traktuj swoje główne trasy jako „dowolną domenę lub subdomenę”. Następnie na kontrolerach spoczywa odpowiedzialność za wyszukanie bieżącej domeny lub subdomeny i zmapowanie jej do odpowiedniego klienta.
Justin French,

Odpowiedzi:

95

W Rails 3 jest to prostsze, jak na http://guides.rubyonrails.org/routing.html#advanced-constraints :

1) zdefiniuj niestandardową klasę ograniczenia w lib/domain_constraint.rb:

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

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

2) użyj tej klasy w swoich trasach z nową składnią bloków

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

root :to => 'main#index'

lub staromodna składnia opcji

root :to => 'mydomain#index', :constraints => DomainConstraint.new('mydomain.com')
Leonid Shevtsov
źródło
6
Ta odpowiedź wydaje mi się znacznie prostsza.
Jared,
7
To świetne rozwiązanie. Jak to działa w środowisku programistycznym?
superluminary
2
@superluminary działa doskonale, jeśli skonfigurujesz domeny lokalne do programowania (na przykład przez /etc/hosts).
Leonid Shevtsov
7
Uwaga: jeśli używasz Pow lokalnie i masz mojadomena.com.dev, request.domainzwraca .com.dev. Zmień request.domainna request.hosti działa idealnie.
Eric Muyser
2
Przekonałem się, że muszę utworzyć nienazwane trasy, aby to zadziałało, w przeciwnym razie pojawia się Invalid route name, already in use: 'root'błąd ... Aby to zrobić, zmieniłem trasę naroot :to => 'mydomain#index', as: nil
Just Lucky Really
6

W Railsach 5 możesz po prostu zrobić to na swoich trasach:

constraints subdomain: 'blogs' do
  match '/' => 'blogs#show'
end
user3033467
źródło