Instradamento delle rotaie per gestire più domini su una singola applicazione


90

Non sono riuscito a trovare una soluzione praticabile a questo problema, nonostante diverse domande simili qui e altrove. Sembra probabile che questa domanda non abbia avuto risposta per Rails 3, quindi ecco qui:

Ho un'applicazione che attualmente consente agli utenti di creare il proprio sottodominio che contiene la loro istanza dell'applicazione. Mentre in Rails 2 era meglio servirsi del subdomain-fu gem, nella versione 3 è notevolmente più semplice, come per Railscast - http://railscasts.com/episodes/221-subdomains-in-rails-3 .

È roba buona, ma voglio anche offrire agli utenti la possibilità di associare il proprio nome di dominio al proprio account. Quindi, sebbene possano avere http://userx.mydomain.com , vorrei che scegliessero di associare anche http://userx.com .

Ho trovato alcuni riferimenti per farlo in Rails 2, ma queste tecniche non sembrano funzionare più (in particolare questa: https://feefighters.com/blog/hosting-multiple-domains-from-a-single-rails -app / ).

Qualcuno può consigliare un modo per utilizzare le route per accettare un dominio arbitrario e passarlo a un controller in modo da poter mostrare il contenuto appropriato?

Aggiornamento : ho ottenuto la maggior parte delle risposte ora, grazie alla risposta tempestiva di Leonid e a un nuovo sguardo al codice. Alla fine ha richiesto un'aggiunta al codice di sottodominio esistente che stavo usando (dalla soluzione Railscast) e quindi aggiunto un po 'a route.rb. Non sono ancora arrivato fino in fondo, ma voglio pubblicare quello che ho finora.

In lib / sottodominio.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

Ho aggiunto la seconda classe a imitazione della prima, che si sa funziona. Aggiungo semplicemente una condizione che assicuri che il dominio in entrata non sia quello per il quale sto ospitando il sito principale.

Questa classe è usata in routes.rb:

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

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

Qui, sto anteponendo il codice del sottodominio esistente (di nuovo, funziona bene) con una stanza per verificare il dominio. Se questo server risponde a quel dominio e non è quello in cui opera il sito principale, inoltra al controller specificato.

E mentre sembra funzionare, non ho ancora funzionato tutto, ma penso che questo particolare problema sia stato risolto.


1
Grazie mille per la tua modifica, Aaron. Adesso sto affrontando la stessa identica situazione. Come domanda di follow-up, come fai in modo che il tuo server accetti qualsiasi dominio che gli viene inoltrato? Presumo che sarebbe un'impostazione nel file .conf, ma non sono sicuro di cosa. Qualsiasi aiuto sarebbe apprezzato!
deadwards

Aaron, sono con te. Voglio fare la stessa cosa. Ma non voglio codificare il dominio. Voglio che tutto venga eseguito a livello di programmazione senza file di zona e riavvii del server web.
Michael K Madison

1
Michael, devi capovolgere il problema. Dichiara esplicitamente e codifica le rotte esclusivamente per la tua applicazione (ad es. Iscrizione) con un vincolo di host o sottodominio, quindi tratta le rotte principali come "qualsiasi dominio o sottodominio". È quindi responsabilità dei controller cercare il dominio o il sottodominio corrente e mapparlo al cliente giusto.
Justin French

Risposte:


95

In realtà è più semplice in Rails 3, come per http://guides.rubyonrails.org/routing.html#advanced-constraints :

1) definire una classe di vincoli personalizzati in lib/domain_constraint.rb:

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

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

2) usa la classe nei tuoi percorsi con la nuova sintassi del blocco

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

root :to => 'main#index'

o la sintassi delle opzioni antiquata

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

6
Questa risposta mi sembra molto più semplice.
Jared

7
Questa è un'ottima soluzione. Come funziona con un ambiente di sviluppo?
superluminaria

2
@superluminary funziona perfettamente se imposti domini locali per lo sviluppo (ad esempio, tramite /etc/hosts).
Leonid Shevtsov

7
Nota: se usi Pow localmente e hai mydomain.com.dev, request.domainrestituisce .com.dev. Cambia request.domainin request.hoste funziona perfettamente.
Eric Muyser

2
Ho scoperto che devo creare percorsi senza nome perché funzioni, altrimenti ottengo l' Invalid route name, already in use: 'root'errore ... Per fare ciò, ho cambiato il percorso inroot :to => 'mydomain#index', as: nil
Just Lucky Really

6

In Rails 5, puoi semplicemente farlo nei tuoi percorsi:

constraints subdomain: 'blogs' do
  match '/' => 'blogs#show'
end
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.