Rails-Routing zur Verarbeitung mehrerer Domänen in einer einzigen Anwendung

89

Ich konnte trotz einiger ähnlicher Fragen hier und anderswo keine praktikable Lösung für dieses Problem finden. Es ist wahrscheinlich, dass diese Frage für Rails 3 nicht beantwortet wurde.

Ich habe eine Anwendung, mit der Benutzer derzeit ihre eigene Subdomain erstellen können, die ihre Instanz der Anwendung enthält. Während Sie in Rails 2 am besten mit dem Subdomain-Fu-Juwel bedient wurden, ist es in Version 3 laut Railscast - http://railscasts.com/episodes/221-subdomains-in-rails-3 - dramatisch einfacher .

Das ist gut, aber ich möchte Benutzern auch die Möglichkeit bieten, ihren eigenen Domainnamen mit ihrem Konto zu verknüpfen. Obwohl sie möglicherweise http://userx.mydomain.com haben , möchte ich, dass sie auch http://userx.com zuordnen .

Ich habe in Rails 2 einige Hinweise dazu gefunden, aber diese Techniken scheinen nicht mehr zu funktionieren (insbesondere diese: https://feefighters.com/blog/hosting-multiple-domains-from-a-single-rails -app / ).

Kann jemand eine Möglichkeit empfehlen, Routen zu verwenden, um eine beliebige Domain zu akzeptieren und an einen Controller weiterzuleiten, damit ich den entsprechenden Inhalt anzeigen kann?

Update : Dank Leonids rechtzeitiger Antwort und einem neuen Blick auf den Code habe ich jetzt die meiste Antwort erhalten. Letztendlich war es erforderlich, den vorhandenen Subdomain-Code, den ich verwendet habe (aus der Railscast-Lösung), zu ergänzen und dann ein bisschen zu route.rb hinzuzufügen. Ich bin noch nicht ganz da, aber ich möchte posten, was ich bisher habe.

In 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

Ich habe die zweite Klasse in Nachahmung der ersten hinzugefügt, von der bekannt ist, dass sie funktioniert. Ich füge einfach eine Bedingung hinzu, die sicherstellt, dass die eingehende Domain nicht die ist, für die ich die Hauptseite hoste.

Diese Klasse wird in route.rb verwendet:

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

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

Hier stelle ich dem vorhandenen Subdomain-Code (wieder funktioniert er einwandfrei) eine Zeilengruppe voran, um nach der Domain zu suchen. Wenn dieser Server auf diese Domäne antwortet und nicht derjenige ist, unter dem der Hauptstandort betrieben wird, leiten Sie ihn an den angegebenen Controller weiter.

Und während das zu funktionieren scheint, habe ich noch nicht alles im Gange, aber ich denke, dieses spezielle Problem wurde gelöst.

Aaron Vegh
quelle
1
Vielen Dank für Ihre Bearbeitung, Aaron. Ich habe es gerade mit genau der gleichen Situation zu tun. Wie können Sie Ihren Server dazu bringen, eine Domain zu akzeptieren, die an ihn weitergeleitet wird? Ich gehe davon aus, dass es sich um eine Einstellung in der .conf-Datei handelt, bin mir aber nicht sicher, was. Jede Hilfe wäre dankbar!
Deadwards
Aaron, ich bin bei dir. Ich möchte das Gleiche tun. Aber ich möchte die Domain nicht fest codieren. Ich möchte, dass alles programmgesteuert ohne Zonendateien und Neustart des Webservers ausgeführt wird.
Michael K Madison
1
Michael, du musst das Problem umdrehen. Deklarieren und codieren Sie die Routen, die ausschließlich für Ihre Anwendung bestimmt sind (z. B. Anmeldung), explizit mit einer Host- oder Subdomain-Einschränkung, und behandeln Sie Ihre Hauptrouten dann als "jede Domain oder Subdomain". Es liegt dann in der Verantwortung Ihrer Controller, die aktuelle Domain oder Subdomain nachzuschlagen und sie dem richtigen Kunden zuzuordnen.
Justin French

Antworten:

95

In Rails 3 ist dies gemäß http://guides.rubyonrails.org/routing.html#advanced-constraints einfacher :

1) Definieren Sie eine benutzerdefinierte Einschränkungsklasse in lib/domain_constraint.rb:

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

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

2) Verwenden Sie die Klasse in Ihren Routen mit der neuen Blocksyntax

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

root :to => 'main#index'

oder die altmodische Optionssyntax

root :to => 'mydomain#index', :constraints => DomainConstraint.new('mydomain.com')
Leonid Shevtsov
quelle
6
Diese Antwort erscheint mir viel einfacher.
Jared
7
Dies ist eine großartige Lösung. Wie funktioniert es mit einer Entwicklungsumgebung?
Superluminary
2
@superluminary funktioniert einwandfrei, wenn Sie lokale Domänen für die Entwicklung einrichten (z. B. via /etc/hosts).
Leonid Shevtsov
7
Hinweis: Wenn Sie Pow lokal verwenden und mydomain.com.dev haben, wird request.domain.com.dev zurückgegeben. Wechseln Sie request.domainzu request.hostund es funktioniert perfekt.
Eric Muyser
2
Ich habe festgestellt, dass ich unbenannte Routen erstellen muss, damit dies funktioniert, sonst erhalte ich den Invalid route name, already in use: 'root'Fehler ... Um dies zu tun, habe ich die Route inroot :to => 'mydomain#index', as: nil
Just Lucky Really
5

In Rails 5 können Sie dies einfach auf Ihren Routen tun:

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