【问题标题】:Subdomains in a Rails 4 appRails 4 应用程序中的子域
【发布时间】:2014-08-31 08:27:00
【问题描述】:

今天我遇到了一个相当奇怪的现象。在开发每个用户都有自己的子域的 Rails 应用程序并尝试使用 Devise 来实现时,我遇到了未注册的子域也会路由到根页面。因此,例如,即使没有(显式)子域,它也会将我路由到主应用程序页面。也许这与我的特定设置有关?我也尝试了一个新的 Rails 项目,但得到了相同的结果。任何人都可以为我澄清这一点? Railscast 没有做到这一点。

另外,我现在正在使用 WEBrick,尽管这不是我将在生产中使用的,并且我正在使用域 lvh.me 来访问子域。

感谢您的帮助。

编辑:这是我的 routes.rb 文件:

Rails.application.routes.draw do
    devise_for :users
    root 'static_page#index'
end

我遵循了 Devise wiki 中的指南: https://github.com/plataformatec/devise/wiki/How-to:-Scope-login-to-subdomain

所以我所做的是通过迁移删除了电子邮件的唯一性,然后我将 :subdomain 添加到 request_keys 中,如下所示:

devise :database_authenticatable, :recoverable, :rememberable, :trackable, :timeoutable, request_keys: [:subdomain]

然后我继续重写“find_for_authentication”函数,如下所示:

def self.find_for_authentication(conditions={})
    conditions[:account_id] = Account.find_by_subdomain(conditions.delete(:subdomain)).id
    super(conditions)
end

这就是总结。

编辑: 我一直在搞砸,我发现了问题。 “根”指令将所有子域都指向我的域。因此,如果我从 routes.rb 中删除根目录,每个 子域都会导致 RouteError。我记得在我的应用程序的某个地方需要一个 root 用于 Devise。所以我不确定这是 Devise 的行为还是 root 的行为。

【问题讨论】:

  • “Railscasts 没有成功”是什么意思?还能为你拼出多少?
  • 对不起,Railscasts 没有明确说明每个子域都被路由到主页的场景,即使没有路由可以做到这一点!
  • 如果您需要帮助修复您的代码,您需要向我们展示您正在使用的代码,然后解释问题。
  • 嗨@Alex,我不熟悉那个 rasilcast 插曲......你能复制你添加的任何其他代码来让那个域的东西工作吗? (注意:一些 railscast 已经很老了,可能依赖于旧版本的 rails - 另外,如果您在此处包含所有代码,我们可能会发现一些明显遗漏的内容)
  • 基本上,我是按照教程进行的,然后我去看了一些 Railscast,看看有没有我可能错过的东西。

标签: ruby-on-rails ruby-on-rails-4 devise subdomain


【解决方案1】:

您可能有几个问题

首先,您需要了解 Devise 在登录后重定向用户的方式,其次是在 Rails 中如何路由子域。

--

设计

默认情况下,Devise routes to current_user_path(通常表示 users#show)或路由中的其他内容:

def after_sign_in_path_for(resource)
  current_user_path
end

这意味着当您接受用户的登录时,他们将被带到自己的路径。根据您的路线,这通常意味着主站点(无子域)用户的路径 (domain.com/users/56) 或其他内容。

如果您的问题没有任何细节,我只能推测这一点。

--

子域

刚刚开发了一些支持子域的应用程序,您应该考虑关于路由到子域的一些事情。

一旦您的用户登录,他们需要能够被路由到特定的subdomain。这样做的方法是使用constraint in your routes:

#config/routes.rb
constraints { subdomain: 'admin' } do
    resources :photos
end

我们发现您无法使用普通路由路径执行此操作 - 您必须使用 url(而不是 path 帮助程序)。例如:

photos_path(subdomain: current_user.name) #-> does not work (path is relative)
photos_url(subdomain: current_user.name) #-> will route to http://name.lvh.me:3000

您必须记住的是,如果您希望将流量重定向/路由到不同的子域,则需要引用帮助程序的 url 形式,而不是 path 引用。

因此,如果您使用如上所示的after_sign_in_path_for,您将需要执行以下操作:

def after_sign_in_path_for(resource)
   root_url(subdomain: resource.name)
end

--

会话

最后,您要确保您的 Devise 会话 cookie 在设置后仍保持初始化状态。我们发现默认情况下不处理子域,因此您必须确保它们得到满足:

Share session (cookies) between subdomains in Rails?

#config/initializers/session_store.rb
YOUR_APP_NAME::Application.config.session_store :cookie_store, key: '_app_name_session', domain: :all, tld_length: 2 

【讨论】:

  • 嗯,我的子域路由工作——只是不是我预期的方式。我正在写一些公司门户:每个公司都有自己的子域,他们可以像这样直接登录:foo.site.com,他们将被称为登录窗口。现在,我在 Account(具有 subdomain 属性的公司)和 User 之间建立了一个 has_many 关联。用户是被管理的设计资源。但是即使存在 no 子域为 'foo' 的公司,但即使我去 foo.site.com,它也能很好地将我路由到登录页面。
【解决方案2】:

我手动解决了。我发现 routes.rb 中的“root”指令接受来自每个子域的请求。最后,我实现了一个自定义约束并将其添加到 routes.rb 文件中 devise_for 的约束中。这充分解决了我的问题。谢谢大家的帮助!

更新:

针对要求我提供代码的评论:我们设置了一个系统,每个帐户(企业帐户)都有自己的子域,每个企业帐户都有很多用户。我的子域约束看起来像

lib/subdomain.rb

class Subdomain
  def self.matches?(request)
    request.subdomain.present? && Account.exists?(subdomain: request.subdomain)
  end
end

然后在我的 config/routes.rb 中,我使用该约束来路由请求:

config/routes.rb

require 'Subdomain'

Rails.application.routes.draw do
  # Some routes...
  constraints(Subdomain) do
    devise_for :users, controllers: {:sessions => 'session'}
    root 'dashboard#index'
    # More subdomain constrained routes...
  end
end

在我发布的原始问题中,我已经展示了我的其余设置。我希望这对某人有所帮助。

【讨论】:

  • 请在 Ruby 中添加一个示例来说明这意味着什么——例如,您的 routes.rb 的相关 sn-p。
  • 我做到了。你现在可以看到我的 routes.rb 和我的子域约束了。
猜你喜欢
  • 1970-01-01
  • 2013-10-17
  • 1970-01-01
  • 2012-06-10
  • 2011-12-29
  • 2014-01-02
  • 1970-01-01
  • 2016-02-15
  • 2011-01-11
相关资源
最近更新 更多