Маршрутизація рейок для обробки декількох доменів в одному додатку


90

Мені не вдалося знайти дієвого вирішення цієї проблеми, незважаючи на кілька подібних питань тут і деінде. Здається імовірним, що на це запитання не було відповіді для 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), а потім додавання трохи до маршрутів.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

Я додав другий клас, наслідуючи перший, який, як відомо, працює. Я просто додаю умову, яка гарантує, що вхідний домен не є тим, для якого я розміщую основний сайт.

Цей клас використовується в routes.rb:

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

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

Тут я додаю існуючий код субдомену (знову ж таки, він працює нормально) за допомогою строфи, щоб перевірити домен. Якщо цей сервер відповідає на цей домен, і це не той, під яким працює основний сайт, перешліть його на вказаний контролер.

І хоча це, здається, працює, у мене ще не все працює, але я думаю, що ця конкретна проблема була вирішена.


1
Велике спасибі за вашу редакцію, Аароне. Зараз я маю справу з точно такою ж ситуацією. Як наступне запитання, як змусити ваш сервер прийняти будь-який домен, який йому пересилається? Я припускаю, що це було б налаштування у файлі .conf, але я не впевнений, що. Будь-яка допомога буде вдячна!
deadwards

Аароне, я з тобою. Я хочу зробити те саме. Але я не хочу жорстко кодувати домен. Я хочу, щоб все це було виконано програмно, без файлів зон і перезапуску веб-сервера.
Michael K Madison

1
Майкл, потрібно перевернути проблему. Явно декларуйте та жорстко кодуйте маршрути, призначені виключно для вашої програми (наприклад, реєстрація), з обмеженням на хост або субдомен, а потім розглядайте основні маршрути як "будь-який домен або субдомен". Тоді відповідальність ваших контролерів полягає у пошуку поточного домену або субдомену та прив'язуванні його до потрібного клієнта.
Джастін Френч

Відповіді:


95

Це насправді простіше в 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')

6
Ця відповідь здається мені набагато простішою.
Джаред,

7
Це чудове рішення. Як це працює з середовищем для розвитку?
надсвітлий

2
@superluminary це чудово працює, якщо ви встановили локальні домени для розробки (наприклад, через /etc/hosts).
Леонід Шевцов

7
Примітка: якщо ви використовуєте Pow локально і маєте mydomain.com.dev, тоді request.domainповертається .com.dev. Змініть request.domainна, request.hostі це працює чудово.
Eric Muyser

2
Я виявив, що мені потрібно створити безіменні маршрути, щоб це працювало, інакше з’являється Invalid route name, already in use: 'root'помилка ... Для цього я змінив маршрут наroot :to => 'mydomain#index', as: nil
Just Lucky Really

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.