Rails routing untuk menangani beberapa domain pada satu aplikasi

90

Saya tidak dapat menemukan solusi yang bisa diterapkan untuk masalah ini, meskipun ada beberapa pertanyaan serupa di sini dan di tempat lain. Sepertinya pertanyaan ini belum terjawab untuk Rails 3, jadi begini:

Saya memiliki aplikasi yang saat ini memungkinkan pengguna untuk membuat subdomain mereka sendiri yang berisi contoh aplikasi mereka. Sementara di Rails 2 Anda paling baik disajikan menggunakan permata subdomain-fu, di versi 3 ini secara dramatis lebih sederhana, sesuai dengan Railscast - http://railscasts.com/episodes/221-subdomains-in-rails-3 .

Itu bagus, tetapi saya juga ingin memberikan opsi bagi pengguna untuk mengaitkan nama domain mereka sendiri dengan akun mereka. Jadi, meskipun mereka mungkin memiliki http://userx.mydomain.com , saya ingin mereka memilih untuk menghubungkan http://userx.com juga.

Saya menemukan beberapa referensi untuk melakukan ini di Rails 2, tetapi teknik tersebut tampaknya tidak berfungsi lagi (terutama yang ini: https://feefighters.com/blog/hosting-multiple-domains-from-a-single-rails -app / ).

Adakah yang bisa merekomendasikan cara untuk menggunakan rute untuk menerima domain sewenang-wenang dan meneruskannya ke pengontrol sehingga saya dapat menampilkan konten yang sesuai?

Pembaruan : Saya mendapatkan sebagian besar jawaban sekarang, berkat tanggapan Leonid yang tepat waktu, dan tampilan baru pada kodenya. Ini pada akhirnya membutuhkan tambahan kode Subdomain yang ada yang saya gunakan (dari solusi Railscast) dan kemudian menambahkan sedikit ke routes.rb. Saya belum jauh-jauh ke sana tetapi saya ingin memposting apa yang saya miliki sejauh ini.

Di 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

Saya telah menambahkan kelas kedua untuk meniru yang pertama, yang dikenal berfungsi. Saya hanya menambahkan ketentuan yang memastikan bahwa domain masuk bukan domain yang saya hosting situs utamanya.

Kelas ini digunakan di routes.rb:

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

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

Di sini, saya mempersiapkan kode subdomain yang ada (sekali lagi, ini berfungsi dengan baik) dengan bait untuk memeriksa Domain. Jika server ini merespons domain itu dan itu bukan yang menjalankan situs utama, teruskan ke pengontrol yang ditentukan.

Dan sementara itu tampaknya berhasil, saya belum memiliki semuanya berfungsi, tetapi saya pikir masalah khusus ini telah terpecahkan.

Aaron Vegh
sumber
1
Terima kasih banyak atas suntingan Anda, Aaron. Saya sedang menghadapi situasi yang sama persis sekarang. Sebagai pertanyaan lanjutan, bagaimana Anda membuat server Anda menerima domain apa pun yang diteruskan ke sana? Saya berasumsi ini akan menjadi pengaturan di file .conf, tapi saya tidak yakin apa. Bantuan apa pun akan dihargai!
Deadwards
Aaron, aku bersamamu. Saya ingin melakukan hal yang sama. Tapi saya tidak ingin melakukan hardcode domain. Saya ingin semuanya dilakukan secara terprogram tanpa file zona dan server web dimulai ulang.
Michael K Madison
1
Michael, kamu perlu membalikkan masalahnya. Nyatakan & hardcode secara eksplisit rute yang secara eksklusif untuk aplikasi Anda (misalnya mendaftar) dengan batasan host atau subdomain, lalu perlakukan rute utama Anda sebagai "domain atau subdomain apa pun". Kemudian tanggung jawab pengontrol Anda untuk mencari domain atau subdomain saat ini dan memetakannya ke pelanggan yang tepat.
Justin French

Jawaban:

95

Ini sebenarnya lebih sederhana di Rails 3, sesuai http://guides.rubyonrails.org/routing.html#advanced-constraints :

1) tentukan kelas batasan khusus di lib/domain_constraint.rb:

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

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

2) gunakan kelas di rute Anda dengan sintaks blok baru

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

root :to => 'main#index'

atau sintaks opsi kuno

root :to => 'mydomain#index', :constraints => DomainConstraint.new('mydomain.com')
Leonid Shevtsov
sumber
6
Jawaban ini tampak lebih sederhana bagi saya.
Jared
7
Ini adalah solusi yang bagus. Bagaimana cara kerjanya dengan lingkungan pengembangan?
superluminary
2
@superluminary berfungsi dengan baik jika Anda menyiapkan domain lokal untuk pengembangan (misalnya, melalui /etc/hosts).
Leonid Shevtsov
7
Catatan: jika Anda menggunakan Pow secara lokal dan memiliki mydomain.com.dev, maka request.domainmengembalikan .com.dev. Ubah request.domainke request.hostdan itu bekerja dengan sempurna.
Eric Muyser
2
Saya telah menemukan bahwa saya harus membuat rute tanpa nama agar ini berfungsi, jika tidak saya mendapatkan Invalid route name, already in use: 'root'kesalahan ... Untuk melakukan ini, saya mengubah rute keroot :to => 'mydomain#index', as: nil
Just Lucky Really
6

Di Rails 5, Anda cukup melakukan ini di rute Anda:

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